From a4ac0dd72301c9e30801e3d7bc6450e16df27f32 Mon Sep 17 00:00:00 2001 From: Shubham Palriwala Date: Sat, 11 Apr 2026 15:02:08 -0700 Subject: [PATCH] Add Agnost MCP analytics integration --- README.md | 1 + package.json | 3 +- scripts/inject-agnost.mjs | 28 +++++++++ src/analytics-setup.mjs | 12 ++++ yarn.lock | 129 +++++++++++++++++++++++++++++++++++++- 5 files changed, 170 insertions(+), 3 deletions(-) create mode 100644 scripts/inject-agnost.mjs create mode 100644 src/analytics-setup.mjs diff --git a/README.md b/README.md index 111c368..778be01 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,7 @@ If you installed from source, change `command` and `args` to point to your local | `LOCALSTACK_AUTH_TOKEN` (**required**) | The LocalStack Auth Token to use for the MCP server | None | | `MAIN_CONTAINER_NAME` | The name of the LocalStack container to use for the MCP server | `localstack-main` | | `MCP_ANALYTICS_DISABLED` | Disable MCP analytics when set to `1` | `0` | +| `AGNOST_ORG_ID` | Agnost organization ID for MCP analytics ([get yours](https://app.agnost.ai)) | None | ## Contributing diff --git a/package.json b/package.json index ce47175..c91e3ac 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "node": ">=20.0.0" }, "scripts": { - "build": "xmcp build", + "build": "xmcp build && cp src/analytics-setup.mjs dist/analytics-setup.mjs && node scripts/inject-agnost.mjs", "dev": "xmcp dev", "start": "node dist/stdio.js", "format": "prettier --write .", @@ -17,6 +17,7 @@ "test:mcp": "yarn test:mcp:direct && yarn test:mcp:evals" }, "dependencies": { + "agnost": "^0.1.10", "dockerode": "^4.0.7", "posthog-node": "5.0.0", "xmcp": "0.6.4", diff --git a/scripts/inject-agnost.mjs b/scripts/inject-agnost.mjs new file mode 100644 index 0000000..8f8b7aa --- /dev/null +++ b/scripts/inject-agnost.mjs @@ -0,0 +1,28 @@ +import { readFileSync, writeFileSync } from "fs"; +import { resolve } from "path"; + +const distFile = resolve(process.cwd(), "dist", "stdio.js"); +const content = readFileSync(distFile, "utf8"); + +// Finds the one place where xmcp creates the server and starts the stdio transport, +// and injects the Agnost setup call between the two. +const pattern = /\}\}(\w+)\(\)\.then\(e=>\{new (\w+)\(e,!1\)\.start\(\)\}\)/; +const match = content.match(pattern); + +if (!match) { + console.error("[agnost] could not find injection point — skipping"); + process.exit(0); +} + +const [full, createServer, StdioTransport] = match; + +const patched = content.replace( + full, + `}}${createServer}().then(async e=>{` + + `try{const{setup}=await import("./analytics-setup.mjs");setup(e);}` + + `catch(e){}` + + `new ${StdioTransport}(e,!1).start()})` +); + +writeFileSync(distFile, patched); +console.log("[agnost] injected"); diff --git a/src/analytics-setup.mjs b/src/analytics-setup.mjs new file mode 100644 index 0000000..8e277c8 --- /dev/null +++ b/src/analytics-setup.mjs @@ -0,0 +1,12 @@ +import { trackMCP } from "agnost"; + +export function setup(server) { + const orgId = process.env.AGNOST_ORG_ID; + if (!orgId || process.env.MCP_ANALYTICS_DISABLED === "1") return; + + trackMCP(server, orgId, { + identify: () => ({ + userId: process.env.LOCALSTACK_AUTH_TOKEN || "anonymous", + }), + }); +} diff --git a/yarn.lock b/yarn.lock index c5bdbc7..2c7f288 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1104,6 +1104,29 @@ "@jsonjoy.com/buffers" "^1.0.0" "@jsonjoy.com/codegen" "^1.0.0" +"@modelcontextprotocol/sdk@^1.18.2": + version "1.29.0" + resolved "https://registry.yarnpkg.com/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz#79786d8b525e269de850ac82b1f1f757f3915f44" + integrity sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ== + dependencies: + "@hono/node-server" "^1.19.9" + ajv "^8.17.1" + ajv-formats "^3.0.1" + content-type "^1.0.5" + cors "^2.8.5" + cross-spawn "^7.0.5" + eventsource "^3.0.2" + eventsource-parser "^3.0.0" + express "^5.2.1" + express-rate-limit "^8.2.1" + hono "^4.11.4" + jose "^6.1.3" + json-schema-typed "^8.0.2" + pkce-challenge "^5.0.0" + raw-body "^3.0.0" + zod "^3.25 || ^4.0" + zod-to-json-schema "^3.25.1" + "@modelcontextprotocol/sdk@^1.25.3", "@modelcontextprotocol/sdk@^1.27.1": version "1.27.1" resolved "https://registry.yarnpkg.com/@modelcontextprotocol/sdk/-/sdk-1.27.1.tgz#a602cf823bf8a68e13e7112f50aeb02b09fb83b9" @@ -1628,6 +1651,17 @@ agent-base@^7.1.2: resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-7.1.4.tgz#e3cd76d4c548ee895d3c3fd8dc1f6c5b9032e7a8" integrity sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ== +agnost@^0.1.10: + version "0.1.10" + resolved "https://registry.yarnpkg.com/agnost/-/agnost-0.1.10.tgz#ceddca9cb7226adef2ad84e5fc62aa58dba082ee" + integrity sha512-zXMsVGeD0KuWcQ6OhpL5wHkF+6eawun1T1wx2tlCheQoGUtclRz/UKdsY9x9LE6gqczxzylmlIiUTN5gaQnPmg== + dependencies: + "@modelcontextprotocol/sdk" "^1.18.2" + axios "^1.4.0" + dotenv "^17.2.2" + uuid "^9.0.0" + zod "^3.25.76" + ai@^6.0.97: version "6.0.116" resolved "https://registry.yarnpkg.com/ai/-/ai-6.0.116.tgz#dc1c3d929453e165fcd3f188d8663617ecf94129" @@ -1743,11 +1777,25 @@ asn1@^0.2.6: dependencies: safer-buffer "~2.1.0" +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + auto-bind@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/auto-bind/-/auto-bind-5.0.1.tgz#50d8e63ea5a1dddcb5e5e36451c1a8266ffbb2ae" integrity sha512-ooviqdwwgfIfNmDwo94wlshcdzfO64XV0Cg6oDsDYBJfITDz1EngD2z7DkbvCWn+XIMsIqW27sEVF6qcpJrRcg== +axios@^1.4.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.15.0.tgz#0fcee91ef03d386514474904b27863b2c683bf4f" + integrity sha512-wWyJDlAatxk30ZJer+GeCWS209sA42X+N5jU2jy6oHTp7ufw8uzUTVFBX9+wTfAlhiJXGS0Bq7X6efruWjuK9Q== + dependencies: + follow-redirects "^1.15.11" + form-data "^4.0.5" + proxy-from-env "^2.1.0" + babel-jest@30.1.2: version "30.1.2" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-30.1.2.tgz#decd53b3a0cafca49443f93fb7a2c0fba55510da" @@ -2094,6 +2142,13 @@ color-name@~1.1.4: resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + commander@^14.0.2: version "14.0.3" resolved "https://registry.yarnpkg.com/commander/-/commander-14.0.3.tgz#425d79b48f9af82fcd9e4fc1ea8af6c5ec07bbc2" @@ -2218,6 +2273,11 @@ define-lazy-prop@^3.0.0: resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz#dbb19adfb746d7fc6d734a06b72f4a00d021255f" integrity sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg== +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + depd@2.0.0, depd@^2.0.0, depd@~2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" @@ -2251,6 +2311,11 @@ dockerode@^4.0.7: tar-fs "~2.1.2" uuid "^10.0.0" +dotenv@^17.2.2: + version "17.4.1" + resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-17.4.1.tgz#d8e2179fe287365ef3aecb9459668454168eda88" + integrity sha512-k8DaKGP6r1G30Lx8V4+pCsLzKr8vLmV2paqEj1Y55GdAgJuIqpRp5FfajGF8KtwMxCz9qJc6wUIJnm053d/WCw== + dunder-proto@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz" @@ -2348,6 +2413,16 @@ es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: dependencies: es-errors "^1.3.0" +es-set-tostringtag@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" + integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== + dependencies: + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + es-toolkit@^1.22.0: version "1.45.1" resolved "https://registry.yarnpkg.com/es-toolkit/-/es-toolkit-1.45.1.tgz#21b28b2bd43178fd4c9c937c445d5bcaccce907b" @@ -2537,6 +2612,11 @@ find-up@^4.0.0, find-up@^4.1.0: locate-path "^5.0.0" path-exists "^4.0.0" +follow-redirects@^1.15.11: + version "1.15.11" + resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.11.tgz#777d73d72a92f8ec4d2e410eb47352a56b8e8340" + integrity sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ== + foreground-child@^3.1.0: version "3.3.1" resolved "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz" @@ -2545,6 +2625,17 @@ foreground-child@^3.1.0: cross-spawn "^7.0.6" signal-exit "^4.0.1" +form-data@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.5.tgz#b49e48858045ff4cbf6b03e1805cebcad3679053" + integrity sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + es-set-tostringtag "^2.1.0" + hasown "^2.0.2" + mime-types "^2.1.12" + formdata-polyfill@^4.0.10: version "4.0.10" resolved "https://registry.yarnpkg.com/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz#24807c31c9d402e002ab3d8c720144ceb8848423" @@ -2630,7 +2721,7 @@ get-east-asian-width@^1.0.0, get-east-asian-width@^1.3.1: resolved "https://registry.yarnpkg.com/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz#ce7008fe345edcf5497a6f557cfa54bc318a9ce7" integrity sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA== -get-intrinsic@^1.2.5, get-intrinsic@^1.3.0: +get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz" integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== @@ -2761,11 +2852,18 @@ has-flag@^4.0.0: resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-symbols@^1.1.0: +has-symbols@^1.0.3, has-symbols@^1.1.0: version "1.1.0" resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz" integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + hasown@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz" @@ -3632,11 +3730,23 @@ micromatch@^4.0.8: braces "^3.0.3" picomatch "^2.3.1" +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + mime-db@^1.54.0: version "1.54.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz" integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ== +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + mime-types@^3.0.0, mime-types@^3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz" @@ -3976,6 +4086,11 @@ proxy-addr@^2.0.7: forwarded "0.2.0" ipaddr.js "1.9.1" +proxy-from-env@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-2.1.0.tgz#a7487568adad577cfaaa7e88c49cab3ab3081aba" + integrity sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA== + pump@^3.0.0: version "3.0.3" resolved "https://registry.npmjs.org/pump/-/pump-3.0.3.tgz" @@ -4643,6 +4758,11 @@ uuid@^10.0.0: resolved "https://registry.npmjs.org/uuid/-/uuid-10.0.0.tgz" integrity sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ== +uuid@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== + v8-to-istanbul@^9.0.1: version "9.3.0" resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz" @@ -4808,3 +4928,8 @@ zod@4.3.6, "zod@^3.25 || ^4.0", zod@^4.3.6: version "4.3.6" resolved "https://registry.yarnpkg.com/zod/-/zod-4.3.6.tgz#89c56e0aa7d2b05107d894412227087885ab112a" integrity sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg== + +zod@^3.25.76: + version "3.25.76" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.25.76.tgz#26841c3f6fd22a6a2760e7ccb719179768471e34" + integrity sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==