@evercam/mcp 0.0.1

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.
Files changed (146) hide show
  1. package/README.md +1017 -0
  2. package/dist/bin/evercam-mcp.d.ts +3 -0
  3. package/dist/bin/evercam-mcp.d.ts.map +1 -0
  4. package/dist/bin/evercam-mcp.js +87 -0
  5. package/dist/bin/evercam-mcp.js.map +1 -0
  6. package/dist/src/auth/auth.d.ts +9 -0
  7. package/dist/src/auth/auth.d.ts.map +1 -0
  8. package/dist/src/auth/auth.js +44 -0
  9. package/dist/src/auth/auth.js.map +1 -0
  10. package/dist/src/auth/tokenStore.d.ts +9 -0
  11. package/dist/src/auth/tokenStore.d.ts.map +1 -0
  12. package/dist/src/auth/tokenStore.js +42 -0
  13. package/dist/src/auth/tokenStore.js.map +1 -0
  14. package/dist/src/cli/auth.d.ts +13 -0
  15. package/dist/src/cli/auth.d.ts.map +1 -0
  16. package/dist/src/cli/auth.js +98 -0
  17. package/dist/src/cli/auth.js.map +1 -0
  18. package/dist/src/cli/doctor.d.ts +4 -0
  19. package/dist/src/cli/doctor.d.ts.map +1 -0
  20. package/dist/src/cli/doctor.js +54 -0
  21. package/dist/src/cli/doctor.js.map +1 -0
  22. package/dist/src/cli/profile.d.ts +10 -0
  23. package/dist/src/cli/profile.d.ts.map +1 -0
  24. package/dist/src/cli/profile.js +53 -0
  25. package/dist/src/cli/profile.js.map +1 -0
  26. package/dist/src/cli/run.d.ts +5 -0
  27. package/dist/src/cli/run.d.ts.map +1 -0
  28. package/dist/src/cli/run.js +63 -0
  29. package/dist/src/cli/run.js.map +1 -0
  30. package/dist/src/cli/serve.d.ts +13 -0
  31. package/dist/src/cli/serve.d.ts.map +1 -0
  32. package/dist/src/cli/serve.js +58 -0
  33. package/dist/src/cli/serve.js.map +1 -0
  34. package/dist/src/cli/tools.d.ts +3 -0
  35. package/dist/src/cli/tools.d.ts.map +1 -0
  36. package/dist/src/cli/tools.js +151 -0
  37. package/dist/src/cli/tools.js.map +1 -0
  38. package/dist/src/config/env.d.ts +3 -0
  39. package/dist/src/config/env.d.ts.map +1 -0
  40. package/dist/src/config/env.js +17 -0
  41. package/dist/src/config/env.js.map +1 -0
  42. package/dist/src/config/profiles.d.ts +17 -0
  43. package/dist/src/config/profiles.d.ts.map +1 -0
  44. package/dist/src/config/profiles.js +56 -0
  45. package/dist/src/config/profiles.js.map +1 -0
  46. package/dist/src/index.d.ts +7 -0
  47. package/dist/src/index.d.ts.map +1 -0
  48. package/dist/src/index.js +7 -0
  49. package/dist/src/index.js.map +1 -0
  50. package/dist/src/server.d.ts +8 -0
  51. package/dist/src/server.d.ts.map +1 -0
  52. package/dist/src/server.js +23 -0
  53. package/dist/src/server.js.map +1 -0
  54. package/dist/src/tools/anpr.d.ts +4 -0
  55. package/dist/src/tools/anpr.d.ts.map +1 -0
  56. package/dist/src/tools/anpr.js +75 -0
  57. package/dist/src/tools/anpr.js.map +1 -0
  58. package/dist/src/tools/bim.d.ts +4 -0
  59. package/dist/src/tools/bim.d.ts.map +1 -0
  60. package/dist/src/tools/bim.js +24 -0
  61. package/dist/src/tools/bim.js.map +1 -0
  62. package/dist/src/tools/cameras.d.ts +4 -0
  63. package/dist/src/tools/cameras.d.ts.map +1 -0
  64. package/dist/src/tools/cameras.js +31 -0
  65. package/dist/src/tools/cameras.js.map +1 -0
  66. package/dist/src/tools/copilot.d.ts +4 -0
  67. package/dist/src/tools/copilot.d.ts.map +1 -0
  68. package/dist/src/tools/copilot.js +58 -0
  69. package/dist/src/tools/copilot.js.map +1 -0
  70. package/dist/src/tools/detections.d.ts +4 -0
  71. package/dist/src/tools/detections.d.ts.map +1 -0
  72. package/dist/src/tools/detections.js +40 -0
  73. package/dist/src/tools/detections.js.map +1 -0
  74. package/dist/src/tools/index.d.ts +4 -0
  75. package/dist/src/tools/index.d.ts.map +1 -0
  76. package/dist/src/tools/index.js +31 -0
  77. package/dist/src/tools/index.js.map +1 -0
  78. package/dist/src/tools/media.d.ts +4 -0
  79. package/dist/src/tools/media.d.ts.map +1 -0
  80. package/dist/src/tools/media.js +38 -0
  81. package/dist/src/tools/media.js.map +1 -0
  82. package/dist/src/tools/mutations.d.ts +8 -0
  83. package/dist/src/tools/mutations.d.ts.map +1 -0
  84. package/dist/src/tools/mutations.js +41 -0
  85. package/dist/src/tools/mutations.js.map +1 -0
  86. package/dist/src/tools/notifications.d.ts +4 -0
  87. package/dist/src/tools/notifications.d.ts.map +1 -0
  88. package/dist/src/tools/notifications.js +21 -0
  89. package/dist/src/tools/notifications.js.map +1 -0
  90. package/dist/src/tools/progressPhotos.d.ts +4 -0
  91. package/dist/src/tools/progressPhotos.d.ts.map +1 -0
  92. package/dist/src/tools/progressPhotos.js +36 -0
  93. package/dist/src/tools/progressPhotos.js.map +1 -0
  94. package/dist/src/tools/projects.d.ts +4 -0
  95. package/dist/src/tools/projects.d.ts.map +1 -0
  96. package/dist/src/tools/projects.js +56 -0
  97. package/dist/src/tools/projects.js.map +1 -0
  98. package/dist/src/tools/ptz.d.ts +4 -0
  99. package/dist/src/tools/ptz.d.ts.map +1 -0
  100. package/dist/src/tools/ptz.js +38 -0
  101. package/dist/src/tools/ptz.js.map +1 -0
  102. package/dist/src/tools/shares.d.ts +4 -0
  103. package/dist/src/tools/shares.d.ts.map +1 -0
  104. package/dist/src/tools/shares.js +11 -0
  105. package/dist/src/tools/shares.js.map +1 -0
  106. package/dist/src/tools/siteAnalytics.d.ts +4 -0
  107. package/dist/src/tools/siteAnalytics.d.ts.map +1 -0
  108. package/dist/src/tools/siteAnalytics.js +51 -0
  109. package/dist/src/tools/siteAnalytics.js.map +1 -0
  110. package/dist/src/tools/snapshots.d.ts +4 -0
  111. package/dist/src/tools/snapshots.d.ts.map +1 -0
  112. package/dist/src/tools/snapshots.js +83 -0
  113. package/dist/src/tools/snapshots.js.map +1 -0
  114. package/dist/src/tools/weather.d.ts +4 -0
  115. package/dist/src/tools/weather.d.ts.map +1 -0
  116. package/dist/src/tools/weather.js +11 -0
  117. package/dist/src/tools/weather.js.map +1 -0
  118. package/dist/src/transports/http.d.ts +24 -0
  119. package/dist/src/transports/http.d.ts.map +1 -0
  120. package/dist/src/transports/http.js +373 -0
  121. package/dist/src/transports/http.js.map +1 -0
  122. package/dist/src/transports/stdio.d.ts +3 -0
  123. package/dist/src/transports/stdio.d.ts.map +1 -0
  124. package/dist/src/transports/stdio.js +6 -0
  125. package/dist/src/transports/stdio.js.map +1 -0
  126. package/dist/src/utils/callTool.d.ts +18 -0
  127. package/dist/src/utils/callTool.d.ts.map +1 -0
  128. package/dist/src/utils/callTool.js +54 -0
  129. package/dist/src/utils/callTool.js.map +1 -0
  130. package/dist/src/utils/errors.d.ts +7 -0
  131. package/dist/src/utils/errors.d.ts.map +1 -0
  132. package/dist/src/utils/errors.js +70 -0
  133. package/dist/src/utils/errors.js.map +1 -0
  134. package/dist/src/utils/logger.d.ts +10 -0
  135. package/dist/src/utils/logger.d.ts.map +1 -0
  136. package/dist/src/utils/logger.js +4 -0
  137. package/dist/src/utils/logger.js.map +1 -0
  138. package/dist/src/utils/retry.d.ts +12 -0
  139. package/dist/src/utils/retry.d.ts.map +1 -0
  140. package/dist/src/utils/retry.js +29 -0
  141. package/dist/src/utils/retry.js.map +1 -0
  142. package/dist/src/utils/toolOutput.d.ts +21 -0
  143. package/dist/src/utils/toolOutput.d.ts.map +1 -0
  144. package/dist/src/utils/toolOutput.js +35 -0
  145. package/dist/src/utils/toolOutput.js.map +1 -0
  146. package/package.json +65 -0
@@ -0,0 +1,54 @@
1
+ import { withRetry } from "./retry.js";
2
+ import { normalizeError } from "./errors.js";
3
+ /**
4
+ * Call an MCP tool handler directly without going through a transport.
5
+ * Used by the HTTP REST endpoint (POST /tools/:toolName).
6
+ *
7
+ * This function accesses private fields on McpServer (_registeredTools,
8
+ * validateToolInput, executeToolHandler). These are undocumented internals.
9
+ * Call validateCallToolInternals() at server startup to catch SDK version
10
+ * breakage early rather than at runtime.
11
+ */
12
+ export async function callToolDirect(server, toolName, args) {
13
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
14
+ const internal = server;
15
+ const tool = internal._registeredTools?.[toolName];
16
+ if (!tool)
17
+ throw new Error(`Tool ${toolName} not found`);
18
+ if (!tool.enabled)
19
+ throw new Error(`Tool ${toolName} disabled`);
20
+ const parsed = await internal.validateToolInput(tool, args, toolName);
21
+ let result;
22
+ try {
23
+ result = await withRetry(() => internal.executeToolHandler(tool, parsed, {}));
24
+ }
25
+ catch (err) {
26
+ const message = normalizeError(err).message;
27
+ return {
28
+ content: [{ type: "text", text: JSON.stringify({ error: message }) }],
29
+ isError: true,
30
+ };
31
+ }
32
+ return result;
33
+ }
34
+ /**
35
+ * Verify that the private MCP SDK fields this module depends on still exist.
36
+ * Call once after McpServer is created and tools are registered.
37
+ * Throws with a clear message if the SDK has changed its internals.
38
+ */
39
+ export function validateCallToolInternals(server) {
40
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
41
+ const internal = server;
42
+ const missing = [];
43
+ if (typeof internal._registeredTools !== "object")
44
+ missing.push("_registeredTools");
45
+ if (typeof internal.validateToolInput !== "function")
46
+ missing.push("validateToolInput");
47
+ if (typeof internal.executeToolHandler !== "function")
48
+ missing.push("executeToolHandler");
49
+ if (missing.length > 0) {
50
+ throw new Error(`MCP SDK private API changed — callTool.ts needs updating. Missing: ${missing.join(", ")}. ` +
51
+ `Check @modelcontextprotocol/sdk release notes.`);
52
+ }
53
+ }
54
+ //# sourceMappingURL=callTool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"callTool.js","sourceRoot":"","sources":["../../../src/utils/callTool.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAE5C;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAiB,EACjB,QAAgB,EAChB,IAAa;IAEb,8DAA8D;IAC9D,MAAM,QAAQ,GAAG,MAAa,CAAA;IAC9B,MAAM,IAAI,GAAG,QAAQ,CAAC,gBAAgB,EAAE,CAAC,QAAQ,CAAC,CAAA;IAElD,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,KAAK,CAAC,QAAQ,QAAQ,YAAY,CAAC,CAAA;IACxD,IAAI,CAAC,IAAI,CAAC,OAAO;QAAE,MAAM,IAAI,KAAK,CAAC,QAAQ,QAAQ,WAAW,CAAC,CAAA;IAE/D,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,iBAAiB,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAA;IAErE,IAAI,MAAe,CAAA;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,SAAS,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,CAAC,CAAA;IAC/E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC,OAAO,CAAA;QAC3C,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC;YAC9E,OAAO,EAAE,IAAI;SACd,CAAA;IACH,CAAC;IAED,OAAO,MAAM,CAAA;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CAAC,MAAiB;IACzD,8DAA8D;IAC9D,MAAM,QAAQ,GAAG,MAAa,CAAA;IAC9B,MAAM,OAAO,GAAa,EAAE,CAAA;IAC5B,IAAI,OAAO,QAAQ,CAAC,gBAAgB,KAAK,QAAQ;QAAE,OAAO,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAA;IACnF,IAAI,OAAO,QAAQ,CAAC,iBAAiB,KAAK,UAAU;QAAE,OAAO,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAA;IACvF,IAAI,OAAO,QAAQ,CAAC,kBAAkB,KAAK,UAAU;QAAE,OAAO,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAA;IACzF,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,KAAK,CACb,sEAAsE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI;YAC1F,gDAAgD,CACnD,CAAA;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,7 @@
1
+ type NormalizedError = {
2
+ status?: number;
3
+ message: string;
4
+ };
5
+ export declare function normalizeError(err: unknown): NormalizedError;
6
+ export {};
7
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/utils/errors.ts"],"names":[],"mappings":"AAAA,KAAK,eAAe,GAAG;IACrB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;CAChB,CAAA;AA0ED,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,GAAG,eAAe,CAO5D"}
@@ -0,0 +1,70 @@
1
+ function redactSecrets(value) {
2
+ return value.replace(/https?:\/\/[^\s]+/g, "[URL]").replace(/[A-Za-z0-9_-]{20,}/g, "[REDACTED]");
3
+ }
4
+ function extractRawMessage(err) {
5
+ if (err && typeof err === "object") {
6
+ const maybeAxios = err;
7
+ if (Array.isArray(maybeAxios.issues)) {
8
+ return { status: 400, message: "Invalid input. Check argument names and value types." };
9
+ }
10
+ const status = maybeAxios.response?.status;
11
+ const body = maybeAxios.response?.data;
12
+ if (typeof body?.message === "string") {
13
+ return { status, message: body.message };
14
+ }
15
+ if (typeof body?.error === "string") {
16
+ return { status, message: body.error };
17
+ }
18
+ if (typeof body === "string" && body.length > 0) {
19
+ return { status, message: body };
20
+ }
21
+ if (typeof maybeAxios.message === "string" && maybeAxios.message.length > 0) {
22
+ return { status, message: maybeAxios.message };
23
+ }
24
+ }
25
+ if (err instanceof Error)
26
+ return { message: err.message };
27
+ return { message: String(err) };
28
+ }
29
+ function mapFriendlyMessage(status, message) {
30
+ if (/timed out|timeout/i.test(message)) {
31
+ return "Request timed out. Retry with a smaller scope or increase --timeout.";
32
+ }
33
+ if (/not authenticated|invalid token|unauthorized/i.test(message)) {
34
+ return "Authentication failed. Run `evercam-mcp auth relogin` and try again.";
35
+ }
36
+ if (/tool .* not found/i.test(message)) {
37
+ return "Tool not found. Run `evercam-mcp tools list` and use an exact tool name.";
38
+ }
39
+ if (/tool .* disabled/i.test(message)) {
40
+ return "Tool is disabled in this server configuration.";
41
+ }
42
+ switch (status) {
43
+ case 400:
44
+ return "Invalid request. Check tool arguments and try again.";
45
+ case 401:
46
+ return "Authentication failed. Run `evercam-mcp auth relogin` and try again.";
47
+ case 403:
48
+ return "Access denied for this operation with the current account/token.";
49
+ case 404:
50
+ return "Requested resource was not found.";
51
+ case 429:
52
+ return "Rate limit exceeded. Wait and retry.";
53
+ case 500:
54
+ case 502:
55
+ case 503:
56
+ case 504:
57
+ return "Evercam service is temporarily unavailable. Please retry shortly.";
58
+ default:
59
+ return message;
60
+ }
61
+ }
62
+ export function normalizeError(err) {
63
+ const extracted = extractRawMessage(err);
64
+ const safeMessage = redactSecrets(extracted.message || "Unknown error");
65
+ return {
66
+ status: extracted.status,
67
+ message: mapFriendlyMessage(extracted.status, safeMessage),
68
+ };
69
+ }
70
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/utils/errors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Structured JSON logger. Writes to stderr to avoid polluting the MCP
3
+ * stdio transport on stdout.
4
+ *
5
+ * Never pass raw tokens or secrets in `meta` — callers must redact first.
6
+ */
7
+ type Level = "info" | "warn" | "error";
8
+ export declare function log(level: Level, msg: string, meta?: Record<string, unknown>): void;
9
+ export {};
10
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../src/utils/logger.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,KAAK,KAAK,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;AAEtC,wBAAgB,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAEnF"}
@@ -0,0 +1,4 @@
1
+ export function log(level, msg, meta) {
2
+ process.stderr.write(JSON.stringify({ ts: new Date().toISOString(), level, msg, ...meta }) + "\n");
3
+ }
4
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../../src/utils/logger.ts"],"names":[],"mappings":"AAQA,MAAM,UAAU,GAAG,CAAC,KAAY,EAAE,GAAW,EAAE,IAA8B;IAC3E,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC,CAAA;AACpG,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Retry with exponential backoff for transient upstream failures.
3
+ * Retries on HTTP 429, 502, 503, 504 only — non-retryable errors are
4
+ * rethrown immediately.
5
+ */
6
+ export interface RetryOptions {
7
+ maxAttempts?: number;
8
+ baseDelayMs?: number;
9
+ maxDelayMs?: number;
10
+ }
11
+ export declare function withRetry<T>(fn: () => Promise<T>, opts?: RetryOptions): Promise<T>;
12
+ //# sourceMappingURL=retry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../../src/utils/retry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,MAAM,WAAW,YAAY;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,wBAAsB,SAAS,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,GAAE,YAAiB,GAAG,OAAO,CAAC,CAAC,CAAC,CAqB5F"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Retry with exponential backoff for transient upstream failures.
3
+ * Retries on HTTP 429, 502, 503, 504 only — non-retryable errors are
4
+ * rethrown immediately.
5
+ */
6
+ const RETRYABLE_STATUSES = new Set([429, 502, 503, 504]);
7
+ export async function withRetry(fn, opts = {}) {
8
+ const maxAttempts = opts.maxAttempts ?? 3;
9
+ const baseDelayMs = opts.baseDelayMs ?? 500;
10
+ const maxDelayMs = opts.maxDelayMs ?? 8_000;
11
+ let lastErr;
12
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
13
+ try {
14
+ return await fn();
15
+ }
16
+ catch (err) {
17
+ // Only retry on known transient HTTP status codes
18
+ const status = err?.response?.status;
19
+ if (!status || !RETRYABLE_STATUSES.has(status) || attempt === maxAttempts) {
20
+ throw err;
21
+ }
22
+ lastErr = err;
23
+ const delay = Math.min(baseDelayMs * 2 ** (attempt - 1), maxDelayMs);
24
+ await new Promise((r) => setTimeout(r, delay));
25
+ }
26
+ }
27
+ throw lastErr;
28
+ }
29
+ //# sourceMappingURL=retry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.js","sourceRoot":"","sources":["../../../src/utils/retry.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,kBAAkB,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,CAAA;AAQxD,MAAM,CAAC,KAAK,UAAU,SAAS,CAAI,EAAoB,EAAE,OAAqB,EAAE;IAC9E,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,CAAC,CAAA;IACzC,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,GAAG,CAAA;IAC3C,MAAM,UAAU,GAAG,IAAI,CAAC,UAAU,IAAI,KAAK,CAAA;IAE3C,IAAI,OAAgB,CAAA;IACpB,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC;QACxD,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,EAAE,CAAA;QACnB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,kDAAkD;YAClD,MAAM,MAAM,GAAI,GAAW,EAAE,QAAQ,EAAE,MAA4B,CAAA;YACnE,IAAI,CAAC,MAAM,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,OAAO,KAAK,WAAW,EAAE,CAAC;gBAC1E,MAAM,GAAG,CAAA;YACX,CAAC;YACD,OAAO,GAAG,GAAG,CAAA;YACb,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,CAAC,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,CAAA;YACpE,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAA;QAChD,CAAC;IACH,CAAC;IACD,MAAM,OAAO,CAAA;AACf,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Wrap any value in the MCP tool content block format.
3
+ * Use this in every tool handler instead of inline JSON.stringify.
4
+ */
5
+ export declare function safeText(data: unknown): {
6
+ content: [{
7
+ type: "text";
8
+ text: string;
9
+ }];
10
+ };
11
+ /**
12
+ * Wrap base64-encoded image data in MCP content format.
13
+ */
14
+ export declare function imageContent(base64: string, mimeType?: string): {
15
+ content: [{
16
+ type: "image";
17
+ data: string;
18
+ mimeType: string;
19
+ }];
20
+ };
21
+ //# sourceMappingURL=toolOutput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolOutput.d.ts","sourceRoot":"","sources":["../../../src/utils/toolOutput.ts"],"names":[],"mappings":"AAiBA;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG;IACvC,OAAO,EAAE,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAC1C,CAGA;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,EACd,QAAQ,SAAe,GACtB;IACD,OAAO,EAAE,CAAC;QAAE,IAAI,EAAE,OAAO,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAC7D,CAIA"}
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Safe serializer for MCP tool responses.
3
+ * Handles BigInt (→ "<n>n") and circular references (→ "[Circular]")
4
+ * so tool handlers never crash on unexpected API response shapes.
5
+ */
6
+ function safeReplacer() {
7
+ const seen = new WeakSet();
8
+ return (_key, value) => {
9
+ if (typeof value === "bigint")
10
+ return value.toString() + "n";
11
+ if (typeof value === "object" && value !== null) {
12
+ if (seen.has(value))
13
+ return "[Circular]";
14
+ seen.add(value);
15
+ }
16
+ return value;
17
+ };
18
+ }
19
+ /**
20
+ * Wrap any value in the MCP tool content block format.
21
+ * Use this in every tool handler instead of inline JSON.stringify.
22
+ */
23
+ export function safeText(data) {
24
+ const text = JSON.stringify(data ?? null, safeReplacer(), 2);
25
+ return { content: [{ type: "text", text }] };
26
+ }
27
+ /**
28
+ * Wrap base64-encoded image data in MCP content format.
29
+ */
30
+ export function imageContent(base64, mimeType = "image/jpeg") {
31
+ return {
32
+ content: [{ type: "image", data: base64, mimeType }],
33
+ };
34
+ }
35
+ //# sourceMappingURL=toolOutput.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolOutput.js","sourceRoot":"","sources":["../../../src/utils/toolOutput.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,SAAS,YAAY;IACnB,MAAM,IAAI,GAAG,IAAI,OAAO,EAAE,CAAA;IAC1B,OAAO,CAAC,IAAY,EAAE,KAAc,EAAE,EAAE;QACtC,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC,QAAQ,EAAE,GAAG,GAAG,CAAA;QAC5D,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YAChD,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC;gBAAE,OAAO,YAAY,CAAA;YACxC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QACjB,CAAC;QACD,OAAO,KAAK,CAAA;IACd,CAAC,CAAA;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,IAAa;IAGpC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,IAAI,IAAI,EAAE,YAAY,EAAE,EAAE,CAAC,CAAC,CAAA;IAC5D,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC,EAAE,CAAA;AACvD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAC1B,MAAc,EACd,QAAQ,GAAG,YAAY;IAIvB,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,OAAgB,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;KAC9D,CAAA;AACH,CAAC"}
package/package.json ADDED
@@ -0,0 +1,65 @@
1
+ {
2
+ "name": "@evercam/mcp",
3
+ "version": "0.0.1",
4
+ "description": "MCP server + CLI for Evercam — cameras, AI, copilot, analytics",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": {
11
+ "types": "./dist/index.d.ts",
12
+ "default": "./dist/index.js"
13
+ }
14
+ }
15
+ },
16
+ "bin": {
17
+ "evercam-mcp": "./dist/bin/evercam-mcp.js"
18
+ },
19
+ "files": [
20
+ "dist"
21
+ ],
22
+ "engines": {
23
+ "node": ">=18"
24
+ },
25
+ "scripts": {
26
+ "build": "tsc && chmod +x dist/bin/evercam-mcp.js",
27
+ "dev": "tsx watch bin/evercam-mcp.ts",
28
+ "start": "node dist/bin/evercam-mcp.js serve",
29
+ "typecheck": "tsc -p tsconfig.json --noEmit",
30
+ "test": "node --test --import tsx/esm tests/smoke.test.ts",
31
+ "prepublishOnly": "pnpm run build"
32
+ },
33
+ "packageManager": "pnpm@9.0.0",
34
+ "keywords": [
35
+ "evercam",
36
+ "mcp",
37
+ "model-context-protocol",
38
+ "cameras",
39
+ "ai"
40
+ ],
41
+ "license": "ISC",
42
+ "dependencies": {
43
+ "@evercam/sdk": "0.4.0",
44
+ "@modelcontextprotocol/sdk": "1.15.0",
45
+ "axios": "^1.7.0",
46
+ "chalk": "^5.3.0",
47
+ "commander": "^12.1.0",
48
+ "cors": "^2.8.6",
49
+ "dotenv": "^16.4.0",
50
+ "express": "^4.21.0",
51
+ "humps": "^2.0.1",
52
+ "moment-timezone": "^0.5.45",
53
+ "open": "^10.1.0",
54
+ "zod": "^3.23.0"
55
+ },
56
+ "devDependencies": {
57
+ "@types/cors": "^2.8.19",
58
+ "@types/express": "^4.17.21",
59
+ "@types/humps": "^2.0.6",
60
+ "@types/node": "^22.0.0",
61
+ "tsx": "^4.19.0",
62
+ "typescript": "^5.6.0"
63
+ },
64
+ "private": false
65
+ }