@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 +44 -56
- package/dist/KnownAgents.d.ts.map +1 -1
- package/dist/KnownAgents.js +6 -11
- package/dist/headers.d.ts +1 -1
- package/dist/headers.d.ts.map +1 -1
- package/dist/headers.js +3 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/types.d.ts +8 -36
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/KnownAgents.ts +11 -60
- package/src/headers.ts +2 -2
- package/src/index.ts +0 -2
- package/src/types.ts +8 -38
- package/src/commerce.ts +0 -68
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
|
|
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
|
|
29
|
+
### Track Pageviews and REST Calls
|
|
30
30
|
|
|
31
|
-
|
|
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
|
-
|
|
37
|
+
MCP calls are skipped automatically by `trackPageviewOrRESTCall`. Use `trackMCPCall` to track MCP calls.
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
65
|
-
|
|
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
|
|
63
|
+
For MCP servers that use `StreamableHTTPServerTransport`, call `trackMCPCall` after connecting the transport and before the transport handles the request.
|
|
79
64
|
|
|
80
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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`
|
|
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
|
|
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
|
-
|
|
162
|
+
## How To Use the Agent Identification API ([Full Docs](https://knownagents.com/docs/identification))
|
|
167
163
|
|
|
168
|
-
|
|
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`
|
|
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
|
-
|
|
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
|
-
|
|
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;
|
|
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"}
|
package/dist/KnownAgents.js
CHANGED
|
@@ -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
|
-
|
|
46
|
-
|
|
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 (!
|
|
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
|
-
|
|
115
|
-
|
|
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
|
|
5
|
+
export declare function getIsACPCall(headers: IncomingHttpHeaders): boolean;
|
|
6
6
|
//# sourceMappingURL=headers.d.ts.map
|
package/dist/headers.d.ts.map
CHANGED
|
@@ -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,
|
|
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.
|
|
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
|
|
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
|
|
2
|
+
export { AgentType, type IdentificationRequest, type IdentificationResult, type TrackPageviewOrRESTCallOptions, type VisitRequest } from "./types";
|
|
3
3
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -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,
|
|
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
|
|
31
|
-
|
|
32
|
-
/** UCP response body
|
|
33
|
-
|
|
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
|
|
67
|
-
|
|
68
|
-
/** The
|
|
69
|
-
|
|
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
|
}
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
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,
|
|
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.
|
|
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"
|
package/src/KnownAgents.ts
CHANGED
|
@@ -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
|
-
|
|
104
|
-
|
|
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 (!
|
|
87
|
+
if (!path || getIsPathExcluded(path) || !method) {
|
|
136
88
|
return
|
|
137
89
|
}
|
|
138
90
|
|
|
139
91
|
const created = new Date()
|
|
140
92
|
|
|
141
|
-
let mcpRequestBody:
|
|
142
|
-
let mcpResponseBody:
|
|
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
|
|
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
|
|
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
|
-
|
|
185
|
-
|
|
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
|
|
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
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
|
|
34
|
-
|
|
35
|
-
/** UCP response body
|
|
36
|
-
|
|
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
|
|
71
|
-
|
|
72
|
-
/** The
|
|
73
|
-
|
|
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
|
-
}
|