@knownagents/sdk 2.0.0 → 2.1.0

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 CHANGED
@@ -24,86 +24,84 @@ const knownAgents = new KnownAgents("YOUR_ACCESS_TOKEN")
24
24
 
25
25
  ## How To Set Up Agent & LLM Analytics ([Full Docs](https://knownagents.com/docs/analytics))
26
26
 
27
- Get realtime insight into the hidden ecosystem of [AI agents and other bots](https://knownagents.com/agents) browsing your website, REST APIs, and [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) servers. Measure human traffic coming from AI chat and search platforms like ChatGPT, Perplexity, and Gemini.
27
+ Get realtime insight into how [AI agents and other bots](https://knownagents.com/agents) browse your web pages, call your [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) endpoints, and purchase products through your [ACP (Agentic Commerce Protocol)](https://www.agenticcommerce.dev/) and [UCP (Universal Commerce Protocol)](https://ucp.dev/) shopping flows. Measure human traffic from AI chat and search platforms like ChatGPT, Claude, and Gemini.
28
28
 
29
- ### Track Pageview and REST Calls
29
+ ### Track Pageviews and REST Calls
30
30
 
31
- To collect pageview and REST API analytics, call `trackPageviewOrRESTCall` with the incoming Node.js request and response.
31
+ Call `trackPageviewOrRESTCall` with the incoming request and outgoing response. If you can, do this in middleware.
32
32
 
33
33
  ```ts
34
34
  knownAgents.trackPageviewOrRESTCall(request, response)
35
35
  ```
36
36
 
37
- For REST APIs that return [ACP (Agentic Commerce Protocol)](https://www.agenticcommerce.dev/) or [UCP (Universal Commerce Protocol)](https://ucp.dev/) commerce metadata, include the response body:
37
+ MCP calls are skipped automatically by `trackPageviewOrRESTCall`. Use `trackMCPCall` to track MCP calls.
38
38
 
39
- ```ts
40
- knownAgents.trackPageviewOrRESTCall(request, response, {
41
- restACPResponseBody: acpResponseBody
42
- })
43
- ```
39
+ High-traffic websites should not use this method. Instead, batch visits and send them periodically with `trackVisits` (see below).
40
+
41
+ #### Agentic Commerce Calls
42
+
43
+ For REST implementations of ACP and UCP, include the response body.
44
44
 
45
45
  ```ts
46
+ // For ACP calls ...
47
+
46
48
  knownAgents.trackPageviewOrRESTCall(request, response, {
47
- restUCPResponseBody: ucpResponseBody
49
+ acpResponseBody: acpResponseBody
48
50
  })
49
51
  ```
50
52
 
51
- The SDK waits for the response to finish, then sends status, headers, duration, and any commerce metadata. Sensitive headers are filtered automatically.
52
-
53
- #### Use Middleware if Possible
54
-
55
- If your framework supports middleware, call `trackPageviewOrRESTCall` there so pageviews and REST calls are tracked from a single place. [MCP](https://modelcontextprotocol.io/) requests are skipped automatically.
56
-
57
53
  ```ts
58
- import express from "express"
59
- import { KnownAgents } from "@knownagents/sdk"
60
-
61
- const app = express()
62
- const knownAgents = new KnownAgents("YOUR_ACCESS_TOKEN")
54
+ // For UCP calls ...
63
55
 
64
- app.use((request, response, next) => {
65
- knownAgents.trackPageviewOrRESTCall(request, response)
66
- next()
67
- })
68
-
69
- app.get("/", (request, response) => {
70
- response.send("Hello, world!")
56
+ knownAgents.trackPageviewOrRESTCall(request, response, {
57
+ ucpResponseBody: ucpResponseBody
71
58
  })
72
-
73
- app.listen(3000, () => console.log("Server running on port 3000"))
74
59
  ```
75
60
 
76
61
  ### Track MCP Calls
77
62
 
78
- For [MCP](https://modelcontextprotocol.io/) servers that use `StreamableHTTPServerTransport`, call `trackMCPCall` after connecting the transport and before the transport handles the request.
63
+ For MCP servers that use `StreamableHTTPServerTransport`, call `trackMCPCall` after connecting the transport and before the transport handles the request.
79
64
 
80
- For MCP calls that return [ACP](https://www.agenticcommerce.dev/) or [UCP](https://ucp.dev/) commerce metadata, the SDK captures the relevant currency and total amount automatically.
81
-
82
- Use this order in your MCP HTTP handler:
65
+ High-traffic websites, or those that use the same transport instance to handle multiple concurrent requests, should not use this method. Instead, batch visits and send them periodically with `trackVisits` (see below).
83
66
 
84
67
  ```ts
68
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"
85
69
  import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"
86
70
 
71
+ // ...
72
+
73
+ const mcpServer = new McpServer({
74
+ name: SERVER_NAME,
75
+ version: SERVER_VERSION,
76
+ })
77
+
87
78
  const transport = new StreamableHTTPServerTransport({
88
79
  sessionIdGenerator: undefined
89
80
  })
90
81
 
82
+ // ...
83
+
91
84
  await mcpServer.connect(transport)
85
+
92
86
  knownAgents.trackMCPCall(request, response, transport)
87
+
93
88
  await transport.handleRequest(request, response, parsedBody)
94
89
  ```
95
90
 
96
- Use `trackVisits` instead if the same transport instance handles concurrent requests.
91
+ #### Agentic Commerce Calls
92
+
93
+ This method will track MCP implementations of ACP and UCP automatically.
97
94
 
98
- ### Batching
95
+ ### Batching for High-Traffic Websites
99
96
 
100
- For high-traffic websites, batch multiple visits together and send them periodically (e.g. every 30 seconds) using `trackVisits`. `trackVisits` can also batch MCP visits; if you do that, include the MCP fields in each `VisitRequest` and do not also call `trackMCPCall` for the same requests. Here's an Express example:
97
+ High-traffic websites should batch multiple visits together and send them periodically (e.g. every 30 seconds) using `trackVisits`. This method can track pageviews, REST, MCP, ACP, and UCP calls. Here's an example with Express middleware:
101
98
 
102
99
  ```ts
103
100
  import express from "express"
104
101
  import { KnownAgents, type VisitRequest } from "@knownagents/sdk"
105
102
 
106
103
  const app = express()
104
+
107
105
  const knownAgents = new KnownAgents("YOUR_ACCESS_TOKEN")
108
106
  const visits: VisitRequest[] = []
109
107
 
@@ -140,13 +138,13 @@ setInterval(() => {
140
138
  - Click **Send a Test Visit**
141
139
  - Click **Realtime**
142
140
 
143
- If your website is correctly connected, you should see visits from the Known Agent in the realtime timeline within a few seconds.
141
+ If your website is correctly connected, you should see visits from a test agent in the realtime timeline within a few seconds.
144
142
 
145
143
  ## How To Set Up Automatic Robots.txt ([Full Docs](https://knownagents.com/docs/robots-txt))
146
144
 
147
- Protect sensitive content from unwanted access and scraping. Generate a continuously updating robots.txt that stays up to date with [all current and future bots](https://knownagents.com/agents) in the specified categories automatically.
145
+ Serve a robots.txt that continuously updates with rules for new [crawlers, scrapers, AI agents, and other bots](https://knownagents.com/agents) as they're discovered.
148
146
 
149
- Use the `generateRobotsTXT` function. Select which `AgentType`s you want to block, and a string specifying which URLs are disallowed (e.g. `"/"` to disallow all paths).
147
+ Use the `generateRobotsTXT` method. Select which `AgentType`s you want to block, and a string specifying which URLs are disallowed (e.g. `"/"` to disallow all paths).
150
148
 
151
149
  ```ts
152
150
  import { AgentType } from "@knownagents/sdk"
@@ -159,29 +157,19 @@ const robotsTxt = await knownAgents.generateRobotsTXT([
159
157
  ], "/")
160
158
  ```
161
159
 
162
- The return value is a plain text robots.txt string. Generate a `robotsTxt` periodically (e.g. once per day), then cache and serve it from your website's `/robots.txt` endpoint.
163
-
164
- ## How To Use Agent Identification ([Full Docs](https://knownagents.com/docs/identification))
160
+ The return value is a plain text robots.txt string. Generate a `robotsTxt` periodically (e.g. once per day, using a cron job). Then, serve it from your website's `/robots.txt` endpoint.
165
161
 
166
- Use the `identifyAgent` and `identifyAgents` functions to identify and verify [AI agents and bots](https://knownagents.com/agents) from network requests using Web Bot Auth (HTTP message signatures), IP matching, or other available methods. This can be useful for implementing access policies based on verified agent identity or enriching your own datasets.
162
+ ## How To Use the Agent Identification API ([Full Docs](https://knownagents.com/docs/identification))
167
163
 
168
- ### Identify a Single Request
164
+ Identify and verify [AI agents and other bots](https://knownagents.com/agents) in your own products, from incoming network requests. Authentication uses Web Bot Auth (HTTP message signatures), IP matching, or other available methods. This API can be useful for implementing access policies based on verified agent identity or enriching your own datasets.
169
165
 
170
- Call `identifyAgent` with the incoming request.
166
+ Call `identifyAgent` to identify a single incoming request:
171
167
 
172
168
  ```ts
173
169
  const identification = await knownAgents.identifyAgent(request)
174
-
175
- if (identification.result === "verified") {
176
- handleVerifiedAgent(identification)
177
- } else if (identification.result === "verification_failed") {
178
- handleFailedVerification(identification)
179
- }
180
170
  ```
181
171
 
182
- ### Identify Multiple Requests
183
-
184
- Use `identifyAgents` to identify multiple requests at once:
172
+ Call `identifyAgents` to identify multiple requests at once:
185
173
 
186
174
  ```ts
187
175
  const identifications = await knownAgents.identifyAgents([
@@ -196,7 +184,7 @@ const identifications = await knownAgents.identifyAgents([
196
184
  ])
197
185
  ```
198
186
 
199
- The functions return an object (or array of objects) with the following fields:
187
+ These methods return an object (or array of objects) with the following fields:
200
188
 
201
189
  - `id`: The identifier from the request (if provided)
202
190
  - `result`: The identification result:
@@ -1 +1 @@
1
- {"version":3,"file":"KnownAgents.d.ts","sourceRoot":"","sources":["../src/KnownAgents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,MAAM,CAAA;AAC3D,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAA;AAavG,OAAO,KAAK,EACR,SAAS,EACT,qBAAqB,EACrB,oBAAoB,EACpB,8BAA8B,EAC9B,YAAY,EACf,MAAM,SAAS,CAAA;AAqChB;;GAEG;AACH,qBAAa,WAAW;IACpB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAQ;IAEpC;;;;OAIG;gBACS,WAAW,EAAE,MAAM;IAI/B;;;;;;;;OAQG;IACH,uBAAuB,CAAC,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,8BAA8B,GAAG,IAAI;IAsC3H;;;;;;;;;OASG;IACH,YAAY,CAAC,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,cAAc,EAAE,SAAS,EAAE,6BAA6B,GAAG,IAAI;IAuEhH;;;;;;OAMG;IACH,WAAW,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAI;IA6B3C;;;;;;;;;OASG;IACG,iBAAiB,CAAC,UAAU,EAAE,SAAS,EAAE,EAAE,QAAQ,GAAE,MAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAoBzF;;;;;;;OAOG;IACG,aAAa,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAmB5E;;;;;;;OAOG;IACG,cAAc,CAAC,QAAQ,EAAE,qBAAqB,EAAE,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;CAsB3F"}
1
+ {"version":3,"file":"KnownAgents.d.ts","sourceRoot":"","sources":["../src/KnownAgents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,MAAM,CAAA;AAC3D,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAA;AAGvG,OAAO,KAAK,EACR,SAAS,EACT,qBAAqB,EACrB,oBAAoB,EACpB,8BAA8B,EAC9B,YAAY,EACf,MAAM,SAAS,CAAA;AAEhB;;GAEG;AACH,qBAAa,WAAW;IACpB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAQ;IAEpC;;;;OAIG;gBACS,WAAW,EAAE,MAAM;IAI/B;;;;;;;;OAQG;IACH,uBAAuB,CAAC,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE,8BAA8B,GAAG,IAAI;IAoC3H;;;;;;;;;OASG;IACH,YAAY,CAAC,OAAO,EAAE,eAAe,EAAE,QAAQ,EAAE,cAAc,EAAE,SAAS,EAAE,6BAA6B,GAAG,IAAI;IAqEhH;;;;;;OAMG;IACH,WAAW,CAAC,QAAQ,EAAE,YAAY,EAAE,GAAG,IAAI;IA6B3C;;;;;;;;;OASG;IACG,iBAAiB,CAAC,UAAU,EAAE,SAAS,EAAE,EAAE,QAAQ,GAAE,MAAY,GAAG,OAAO,CAAC,MAAM,CAAC;IAoBzF;;;;;;;OAOG;IACG,aAAa,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAmB5E;;;;;;;OAOG;IACG,cAAc,CAAC,QAAQ,EAAE,qBAAqB,EAAE,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;CAsB3F"}
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.KnownAgents = void 0;
4
- const commerce_1 = require("./commerce");
5
4
  const headers_1 = require("./headers");
6
5
  const paths_1 = require("./paths");
7
6
  /**
@@ -42,10 +41,8 @@ class KnownAgents {
42
41
  response_status_code: response?.statusCode,
43
42
  response_headers: response.getHeaders(),
44
43
  response_duration_in_milliseconds: responseDurationInMilliseconds,
45
- acp_response_currency: options?.restACPResponseBody ? (0, commerce_1.getRESTACPCurrencyIfPossible)(options?.restACPResponseBody) : undefined,
46
- acp_response_total_amount: options?.restACPResponseBody ? (0, commerce_1.getRESTACPTotalAmountIfPossible)(options?.restACPResponseBody) : undefined,
47
- ucp_response_currency: options?.restUCPResponseBody ? (0, commerce_1.getRESTUCPCurrencyIfPossible)(options?.restUCPResponseBody) : undefined,
48
- ucp_response_total_amount: options?.restUCPResponseBody ? (0, commerce_1.getRESTUCPTotalAmountIfPossible)(options?.restUCPResponseBody) : undefined,
44
+ acp_response_body: options?.acpResponseBody,
45
+ ucp_response_body: options?.ucpResponseBody,
49
46
  created: created.toISOString()
50
47
  };
51
48
  this.trackVisits([visitRequest]);
@@ -68,10 +65,9 @@ class KnownAgents {
68
65
  * @param transport - The MCP streamable HTTP transport handling the request.
69
66
  */
70
67
  trackMCPCall(request, response, transport) {
71
- const isMCPCall = (0, headers_1.getIsMCPCall)(request.headers);
72
68
  const path = request.url;
73
69
  const method = request.method;
74
- if (!isMCPCall || !path || (0, paths_1.getIsPathExcluded)(path) || !method) {
70
+ if (!path || (0, paths_1.getIsPathExcluded)(path) || !method) {
75
71
  return;
76
72
  }
77
73
  const created = new Date();
@@ -97,6 +93,7 @@ class KnownAgents {
97
93
  return;
98
94
  }
99
95
  const responseDurationInMilliseconds = Date.now() - created.getTime();
96
+ const mcpResponseResult = mcpResponseBody.result?.structuredContent ?? mcpResponseBody.result;
100
97
  const visitRequest = {
101
98
  request_path: path,
102
99
  request_method: method,
@@ -111,10 +108,8 @@ class KnownAgents {
111
108
  mcp_response_result_is_error: mcpResponseBody.result?.isError,
112
109
  mcp_response_error_code: mcpResponseBody.error?.code,
113
110
  mcp_response_error_message: mcpResponseBody.error?.message,
114
- acp_response_currency: (0, commerce_1.getMCPACPCurrencyIfPossible)(request, mcpResponseBody),
115
- acp_response_total_amount: (0, commerce_1.getMCPACPTotalAmountIfPossible)(request, mcpResponseBody),
116
- ucp_response_currency: (0, commerce_1.getMCPUCPCurrencyIfPossible)(request, mcpResponseBody),
117
- ucp_response_total_amount: (0, commerce_1.getMCPUCPTotalAmountIfPossible)(request, mcpResponseBody),
111
+ acp_response_body: (0, headers_1.getIsACPCall)(request.headers) ? mcpResponseResult : undefined,
112
+ ucp_response_body: (0, headers_1.getIsUCPCall)(request.headers) ? mcpResponseResult : undefined,
118
113
  created: created.toISOString()
119
114
  };
120
115
  this.trackVisits([visitRequest]);
package/dist/headers.d.ts CHANGED
@@ -2,5 +2,5 @@ import type { IncomingHttpHeaders, OutgoingHttpHeaders } from "http";
2
2
  export declare function getFilteredHeaders<Headers extends IncomingHttpHeaders | OutgoingHttpHeaders>(headers: Headers): Headers;
3
3
  export declare function getIsMCPCall(headers: IncomingHttpHeaders): boolean;
4
4
  export declare function getIsUCPCall(headers: IncomingHttpHeaders): boolean;
5
- export declare function getIsProbablyACPCall(headers: IncomingHttpHeaders): boolean;
5
+ export declare function getIsACPCall(headers: IncomingHttpHeaders): boolean;
6
6
  //# sourceMappingURL=headers.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"headers.d.ts","sourceRoot":"","sources":["../src/headers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,MAAM,CAAA;AA2BpE,wBAAgB,kBAAkB,CAAC,OAAO,SAAS,mBAAmB,GAAG,mBAAmB,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAUvH;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAIlE;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAIlE;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAI1E"}
1
+ {"version":3,"file":"headers.d.ts","sourceRoot":"","sources":["../src/headers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,MAAM,CAAA;AA2BpE,wBAAgB,kBAAkB,CAAC,OAAO,SAAS,mBAAmB,GAAG,mBAAmB,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAUvH;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAIlE;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAIlE;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAIlE"}
package/dist/headers.js CHANGED
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getFilteredHeaders = getFilteredHeaders;
4
4
  exports.getIsMCPCall = getIsMCPCall;
5
5
  exports.getIsUCPCall = getIsUCPCall;
6
- exports.getIsProbablyACPCall = getIsProbablyACPCall;
6
+ exports.getIsACPCall = getIsACPCall;
7
7
  const filteredHeaderNames = [
8
8
  "authorization",
9
9
  "proxy-authorization",
@@ -47,8 +47,8 @@ function getIsUCPCall(headers) {
47
47
  return key.toLowerCase() === "ucp-agent";
48
48
  });
49
49
  }
50
- function getIsProbablyACPCall(headers) {
51
- return Object.keys(headers).some((key) => {
50
+ function getIsACPCall(headers) {
51
+ return !getIsUCPCall(headers) && Object.keys(headers).some((key) => {
52
52
  return key.toLowerCase() === "api-version";
53
53
  });
54
54
  }
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export { KnownAgents } from "./KnownAgents";
2
- export { AgentType, type IdentificationRequest, type IdentificationResult, type RESTACPResponseBody, type RESTUCPResponseBody, type TrackPageviewOrRESTCallOptions, type VisitRequest } from "./types";
2
+ export { AgentType, type IdentificationRequest, type IdentificationResult, type TrackPageviewOrRESTCallOptions, type VisitRequest } from "./types";
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EACH,SAAS,EACT,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,mBAAmB,EACxB,KAAK,8BAA8B,EACnC,KAAK,YAAY,EACpB,MAAM,SAAS,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAA;AAC3C,OAAO,EACH,SAAS,EACT,KAAK,qBAAqB,EAC1B,KAAK,oBAAoB,EACzB,KAAK,8BAA8B,EACnC,KAAK,YAAY,EACpB,MAAM,SAAS,CAAA"}
package/dist/types.d.ts CHANGED
@@ -1,36 +1,12 @@
1
1
  import type { IncomingHttpHeaders, OutgoingHttpHeaders } from "http";
2
- /**
3
- * ACP response details from a REST API call.
4
- */
5
- export interface RESTACPResponseBody {
6
- /** The response currency, usually an ISO 4217 code. */
7
- currency?: string;
8
- /** ACP totals returned by the REST endpoint. The "total" item is sent to Known Agents. */
9
- totals?: {
10
- type?: string;
11
- amount?: number;
12
- }[];
13
- }
14
- /**
15
- * UCP response details from a REST API call.
16
- */
17
- export interface RESTUCPResponseBody {
18
- /** The response currency, usually an ISO 4217 code. */
19
- currency?: string;
20
- /** UCP totals returned by the REST endpoint. The "total" item is sent to Known Agents. */
21
- totals?: {
22
- type?: string;
23
- amount?: number;
24
- }[];
25
- }
26
2
  /**
27
3
  * Additional metadata to include when tracking a pageview or REST API call.
28
4
  */
29
5
  export interface TrackPageviewOrRESTCallOptions {
30
- /** ACP response body from the REST endpoint. */
31
- restACPResponseBody?: RESTACPResponseBody;
32
- /** UCP response body from the REST endpoint. */
33
- restUCPResponseBody?: RESTUCPResponseBody;
6
+ /** The ACP response body. */
7
+ acpResponseBody?: Record<string, unknown>;
8
+ /** The UCP response body. */
9
+ ucpResponseBody?: Record<string, unknown>;
34
10
  }
35
11
  /**
36
12
  * A normalized visit payload for the Known Agents API.
@@ -63,14 +39,10 @@ export interface VisitRequest {
63
39
  mcp_response_error_code?: number;
64
40
  /** The MCP response error message */
65
41
  mcp_response_error_message?: string;
66
- /** The ACP response currency */
67
- acp_response_currency?: string;
68
- /** The ACP response "total" amount */
69
- acp_response_total_amount?: number;
70
- /** The UCP response currency */
71
- ucp_response_currency?: string;
72
- /** The UCP response "total" amount */
73
- ucp_response_total_amount?: number;
42
+ /** The ACP response body */
43
+ acp_response_body?: Record<string, unknown>;
44
+ /** The UCP response body */
45
+ ucp_response_body?: Record<string, unknown>;
74
46
  /** The timestamp when the visit occurred (ISO 8601 format) */
75
47
  created?: string;
76
48
  }
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,MAAM,CAAA;AAEpE;;GAEG;AACH,MAAM,WAAW,8BAA8B;IAC3C,6BAA6B;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IACzC,6BAA6B;IAC7B,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAC5C;AAED;;;GAGG;AACH,MAAM,WAAW,YAAY;IACzB,2EAA2E;IAC3E,YAAY,EAAE,MAAM,CAAA;IACpB,2CAA2C;IAC3C,cAAc,EAAE,MAAM,CAAA;IACtB,8EAA8E;IAC9E,eAAe,EAAE,mBAAmB,CAAA;IACpC,oDAAoD;IACpD,oBAAoB,CAAC,EAAE,MAAM,CAAA;IAC7B,+EAA+E;IAC/E,gBAAgB,CAAC,EAAE,mBAAmB,CAAA;IACtC,4CAA4C;IAC5C,iCAAiC,CAAC,EAAE,MAAM,CAAA;IAC1C,sCAAsC;IACtC,kBAAkB,CAAC,EAAE,MAAM,CAAA;IAC3B,gCAAgC;IAChC,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,kCAAkC;IAClC,4BAA4B,CAAC,EAAE,MAAM,CAAA;IACrC,qCAAqC;IACrC,+BAA+B,CAAC,EAAE,MAAM,CAAA;IACxC,kDAAkD;IAClD,4BAA4B,CAAC,EAAE,OAAO,CAAA;IACtC,kCAAkC;IAClC,uBAAuB,CAAC,EAAE,MAAM,CAAA;IAChC,qCAAqC;IACrC,0BAA0B,CAAC,EAAE,MAAM,CAAA;IACnC,4BAA4B;IAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC3C,4BAA4B;IAC5B,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC3C,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IAClC,4FAA4F;IAC5F,EAAE,CAAC,EAAE,MAAM,CAAA;IACX,8EAA8E;IAC9E,eAAe,EAAE,mBAAmB,CAAA;CACvC;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACjC,oDAAoD;IACpD,EAAE,CAAC,EAAE,MAAM,CAAA;IACX;;;;;;OAMG;IACH,MAAM,EAAE,UAAU,GAAG,qBAAqB,GAAG,eAAe,GAAG,gBAAgB,CAAA;IAC/E,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,0DAA0D;IAC1D,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,qDAAqD;IACrD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,kFAAkF;IAClF,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,8DAA8D;IAC9D,aAAa,CAAC,EAAE,MAAM,CAAA;CACzB;AAED;;GAEG;AACH,oBAAY,SAAS;IACjB,OAAO,aAAa;IACpB,WAAW,iBAAiB;IAC5B,aAAa,oBAAoB;IACjC,cAAc,qBAAqB;IACnC,aAAa,oBAAoB;IACjC,eAAe,sBAAsB;IACrC,QAAQ,aAAa;IACrB,cAAc,oBAAoB;IAClC,eAAe,qBAAqB;IACpC,OAAO,YAAY;IACnB,oBAAoB,0BAA0B;IAC9C,OAAO,YAAY;IACnB,UAAU,gBAAgB;IAC1B,mBAAmB,0BAA0B;IAC7C,eAAe,qBAAqB;IACpC,mBAAmB,0BAA0B;CAChD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knownagents/sdk",
3
- "version": "2.0.0",
3
+ "version": "2.1.0",
4
4
  "description": "The official Node.js SDK for Known Agents: AI agent analytics (bot traffic), LLM referral tracking, automatic robots.txt, agent verification",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -1,16 +1,6 @@
1
1
  import type { IncomingMessage, ServerResponse } from "http"
2
2
  import type { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js"
3
- import {
4
- getMCPACPCurrencyIfPossible,
5
- getMCPACPTotalAmountIfPossible,
6
- getMCPUCPCurrencyIfPossible,
7
- getMCPUCPTotalAmountIfPossible,
8
- getRESTACPCurrencyIfPossible,
9
- getRESTACPTotalAmountIfPossible,
10
- getRESTUCPCurrencyIfPossible,
11
- getRESTUCPTotalAmountIfPossible
12
- } from "./commerce"
13
- import { getFilteredHeaders, getIsMCPCall } from "./headers"
3
+ import { getFilteredHeaders, getIsACPCall, getIsMCPCall, getIsUCPCall } from "./headers"
14
4
  import { getIsPathExcluded } from "./paths"
15
5
  import type {
16
6
  AgentType,
@@ -20,41 +10,6 @@ import type {
20
10
  VisitRequest
21
11
  } from "./types"
22
12
 
23
- interface MCPRequestBody {
24
- jsonrpc: string
25
- method: string
26
- params?: {
27
- name?: string
28
- clientInfo?: {
29
- name?: string
30
- version?: string
31
- }
32
- }
33
- }
34
-
35
- interface MCPResponseBody {
36
- jsonrpc: string
37
- result?: {
38
- isError?: boolean
39
- currency?: string
40
- totals?: {
41
- type?: string
42
- amount?: number
43
- }[]
44
- structuredContent?: {
45
- currency?: string
46
- totals?: {
47
- type?: string
48
- amount?: number
49
- }[]
50
- }
51
- }
52
- error?: {
53
- code?: number
54
- message?: string
55
- }
56
- }
57
-
58
13
  /**
59
14
  * Server-side client for Known Agents analytics, robots.txt generation, and agent identification.
60
15
  */
@@ -100,10 +55,8 @@ export class KnownAgents {
100
55
  response_status_code: response?.statusCode,
101
56
  response_headers: response.getHeaders(),
102
57
  response_duration_in_milliseconds: responseDurationInMilliseconds,
103
- acp_response_currency: options?.restACPResponseBody ? getRESTACPCurrencyIfPossible(options?.restACPResponseBody) : undefined,
104
- acp_response_total_amount: options?.restACPResponseBody ? getRESTACPTotalAmountIfPossible(options?.restACPResponseBody) : undefined,
105
- ucp_response_currency: options?.restUCPResponseBody ? getRESTUCPCurrencyIfPossible(options?.restUCPResponseBody) : undefined,
106
- ucp_response_total_amount: options?.restUCPResponseBody ? getRESTUCPTotalAmountIfPossible(options?.restUCPResponseBody) : undefined,
58
+ acp_response_body: options?.acpResponseBody,
59
+ ucp_response_body: options?.ucpResponseBody,
107
60
  created: created.toISOString()
108
61
  }
109
62
 
@@ -128,28 +81,27 @@ export class KnownAgents {
128
81
  * @param transport - The MCP streamable HTTP transport handling the request.
129
82
  */
130
83
  trackMCPCall(request: IncomingMessage, response: ServerResponse, transport: StreamableHTTPServerTransport): void {
131
- const isMCPCall = getIsMCPCall(request.headers)
132
84
  const path = request.url
133
85
  const method = request.method
134
86
 
135
- if (!isMCPCall || !path || getIsPathExcluded(path) || !method) {
87
+ if (!path || getIsPathExcluded(path) || !method) {
136
88
  return
137
89
  }
138
90
 
139
91
  const created = new Date()
140
92
 
141
- let mcpRequestBody: MCPRequestBody | undefined
142
- let mcpResponseBody: MCPResponseBody | undefined
93
+ let mcpRequestBody: any
94
+ let mcpResponseBody: any
143
95
 
144
96
  const originalTransportOnMessage = transport.onmessage
145
97
  transport.onmessage = (message, extra): void => {
146
- mcpRequestBody = message as MCPRequestBody
98
+ mcpRequestBody = message
147
99
  originalTransportOnMessage?.(message, extra)
148
100
  }
149
101
 
150
102
  const originalTransportSend = transport.send
151
103
  transport.send = async (message, options): Promise<void> => {
152
- mcpResponseBody = message as MCPResponseBody
104
+ mcpResponseBody = message
153
105
  await originalTransportSend.call(transport, message, options)
154
106
  }
155
107
 
@@ -166,6 +118,7 @@ export class KnownAgents {
166
118
  }
167
119
 
168
120
  const responseDurationInMilliseconds = Date.now() - created.getTime()
121
+ const mcpResponseResult = mcpResponseBody.result?.structuredContent ?? mcpResponseBody.result
169
122
 
170
123
  const visitRequest: VisitRequest = {
171
124
  request_path: path,
@@ -181,10 +134,8 @@ export class KnownAgents {
181
134
  mcp_response_result_is_error: mcpResponseBody.result?.isError,
182
135
  mcp_response_error_code: mcpResponseBody.error?.code,
183
136
  mcp_response_error_message: mcpResponseBody.error?.message,
184
- acp_response_currency: getMCPACPCurrencyIfPossible(request, mcpResponseBody),
185
- acp_response_total_amount: getMCPACPTotalAmountIfPossible(request, mcpResponseBody),
186
- ucp_response_currency: getMCPUCPCurrencyIfPossible(request, mcpResponseBody),
187
- ucp_response_total_amount: getMCPUCPTotalAmountIfPossible(request, mcpResponseBody),
137
+ acp_response_body: getIsACPCall(request.headers) ? mcpResponseResult : undefined,
138
+ ucp_response_body: getIsUCPCall(request.headers) ? mcpResponseResult : undefined,
188
139
  created: created.toISOString()
189
140
  }
190
141
 
package/src/headers.ts CHANGED
@@ -49,8 +49,8 @@ export function getIsUCPCall(headers: IncomingHttpHeaders): boolean {
49
49
  })
50
50
  }
51
51
 
52
- export function getIsProbablyACPCall(headers: IncomingHttpHeaders): boolean {
53
- return Object.keys(headers).some((key) => {
52
+ export function getIsACPCall(headers: IncomingHttpHeaders): boolean {
53
+ return !getIsUCPCall(headers) && Object.keys(headers).some((key) => {
54
54
  return key.toLowerCase() === "api-version"
55
55
  })
56
56
  }
package/src/index.ts CHANGED
@@ -3,8 +3,6 @@ export {
3
3
  AgentType,
4
4
  type IdentificationRequest,
5
5
  type IdentificationResult,
6
- type RESTACPResponseBody,
7
- type RESTUCPResponseBody,
8
6
  type TrackPageviewOrRESTCallOptions,
9
7
  type VisitRequest
10
8
  } from "./types"
package/src/types.ts CHANGED
@@ -1,39 +1,13 @@
1
1
  import type { IncomingHttpHeaders, OutgoingHttpHeaders } from "http"
2
2
 
3
- /**
4
- * ACP response details from a REST API call.
5
- */
6
- export interface RESTACPResponseBody {
7
- /** The response currency, usually an ISO 4217 code. */
8
- currency?: string
9
- /** ACP totals returned by the REST endpoint. The "total" item is sent to Known Agents. */
10
- totals?: {
11
- type?: string
12
- amount?: number
13
- }[]
14
- }
15
-
16
- /**
17
- * UCP response details from a REST API call.
18
- */
19
- export interface RESTUCPResponseBody {
20
- /** The response currency, usually an ISO 4217 code. */
21
- currency?: string
22
- /** UCP totals returned by the REST endpoint. The "total" item is sent to Known Agents. */
23
- totals?: {
24
- type?: string
25
- amount?: number
26
- }[]
27
- }
28
-
29
3
  /**
30
4
  * Additional metadata to include when tracking a pageview or REST API call.
31
5
  */
32
6
  export interface TrackPageviewOrRESTCallOptions {
33
- /** ACP response body from the REST endpoint. */
34
- restACPResponseBody?: RESTACPResponseBody
35
- /** UCP response body from the REST endpoint. */
36
- restUCPResponseBody?: RESTUCPResponseBody
7
+ /** The ACP response body. */
8
+ acpResponseBody?: Record<string, unknown>
9
+ /** The UCP response body. */
10
+ ucpResponseBody?: Record<string, unknown>
37
11
  }
38
12
 
39
13
  /**
@@ -67,14 +41,10 @@ export interface VisitRequest {
67
41
  mcp_response_error_code?: number
68
42
  /** The MCP response error message */
69
43
  mcp_response_error_message?: string
70
- /** The ACP response currency */
71
- acp_response_currency?: string
72
- /** The ACP response "total" amount */
73
- acp_response_total_amount?: number
74
- /** The UCP response currency */
75
- ucp_response_currency?: string
76
- /** The UCP response "total" amount */
77
- ucp_response_total_amount?: number
44
+ /** The ACP response body */
45
+ acp_response_body?: Record<string, unknown>
46
+ /** The UCP response body */
47
+ ucp_response_body?: Record<string, unknown>
78
48
  /** The timestamp when the visit occurred (ISO 8601 format) */
79
49
  created?: string
80
50
  }
package/src/commerce.ts DELETED
@@ -1,68 +0,0 @@
1
- import type { IncomingMessage } from "http"
2
- import { getIsProbablyACPCall, getIsUCPCall } from "./headers"
3
- import type { RESTACPResponseBody, RESTUCPResponseBody } from "./types"
4
-
5
- interface MCPCommerceResponseBody {
6
- result?: {
7
- currency?: string
8
- totals?: {
9
- type?: string
10
- amount?: number
11
- }[]
12
- structuredContent?: {
13
- currency?: string
14
- totals?: {
15
- type?: string
16
- amount?: number
17
- }[]
18
- }
19
- }
20
- }
21
-
22
- export function getRESTACPCurrencyIfPossible(restACPResponseBody: RESTACPResponseBody): string | undefined {
23
- return restACPResponseBody?.currency
24
- }
25
-
26
- export function getRESTACPTotalAmountIfPossible(restACPResponseBody: RESTACPResponseBody): number | undefined {
27
- return restACPResponseBody?.totals?.find((total) => {
28
- return total.type == "total"
29
- })?.amount
30
- }
31
-
32
- export function getMCPACPCurrencyIfPossible(request: IncomingMessage, mcpResponseBody: MCPCommerceResponseBody): string | undefined {
33
- const isProbablyACP = !getIsUCPCall(request.headers) && getIsProbablyACPCall(request.headers)
34
- return isProbablyACP ? mcpResponseBody.result?.currency : undefined
35
- }
36
-
37
- export function getMCPACPTotalAmountIfPossible(request: IncomingMessage, mcpResponseBody: MCPCommerceResponseBody): number | undefined {
38
- const isProbablyACP = !getIsUCPCall(request.headers) && getIsProbablyACPCall(request.headers)
39
- return isProbablyACP
40
- ? mcpResponseBody.result?.totals?.find((total) => {
41
- return total.type == "total"
42
- })?.amount
43
- : undefined
44
- }
45
-
46
- export function getRESTUCPCurrencyIfPossible(restUCPResponseBody: RESTUCPResponseBody): string | undefined {
47
- return restUCPResponseBody?.currency
48
- }
49
-
50
- export function getRESTUCPTotalAmountIfPossible(restUCPResponseBody: RESTUCPResponseBody): number | undefined {
51
- return restUCPResponseBody?.totals?.find((total) => {
52
- return total.type == "total"
53
- })?.amount
54
- }
55
-
56
- export function getMCPUCPCurrencyIfPossible(request: IncomingMessage, mcpResponseBody: MCPCommerceResponseBody): string | undefined {
57
- const isUCP = getIsUCPCall(request.headers)
58
- return isUCP ? mcpResponseBody.result?.structuredContent?.currency : undefined
59
- }
60
-
61
- export function getMCPUCPTotalAmountIfPossible(request: IncomingMessage, mcpResponseBody: MCPCommerceResponseBody): number | undefined {
62
- const isUCP = getIsUCPCall(request.headers)
63
- return isUCP
64
- ? mcpResponseBody.result?.structuredContent?.totals?.find((total) => {
65
- return total.type == "total"
66
- })?.amount
67
- : undefined
68
- }