frisk-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.
- package/LICENSE +21 -0
- package/README.md +102 -0
- package/dist/index.js +94 -0
- package/dist/index.js.map +1 -0
- package/package.json +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Frisk contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# frisk-mcp
|
|
2
|
+
|
|
3
|
+
An [MCP](https://modelcontextprotocol.io) server for [Frisk](https://github.com/Jiangw2718i/frisk):
|
|
4
|
+
screen the counterparty of an x402 payment before an agent pays it.
|
|
5
|
+
|
|
6
|
+
It exposes one tool, `screen_payment`, which runs Frisk's deterministic checks —
|
|
7
|
+
address sanity, dynamic-`payTo` comparison, transport safety, and your own
|
|
8
|
+
spending policy — and returns `allow` / `review` / `block` with reasons.
|
|
9
|
+
|
|
10
|
+
## Where this belongs, and where it does not
|
|
11
|
+
|
|
12
|
+
An MCP tool runs when a model decides to call it. A payment check that the model
|
|
13
|
+
can skip is a weaker guarantee than the same check on the code path that signs
|
|
14
|
+
the payment.
|
|
15
|
+
|
|
16
|
+
So:
|
|
17
|
+
|
|
18
|
+
- **Use the library** — [`frisk-screen`](https://www.npmjs.com/package/frisk-screen) —
|
|
19
|
+
where the money actually moves. It is MIT, dependency-free, and runs locally.
|
|
20
|
+
- **Use this server** for inspection ("is this address safe to pay?"), and for
|
|
21
|
+
agents that cannot import a library.
|
|
22
|
+
|
|
23
|
+
Frisk is advisory in both cases: it returns a verdict and your code decides. It
|
|
24
|
+
never holds funds and cannot stop a payment by itself.
|
|
25
|
+
|
|
26
|
+
## Install
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
npx frisk-mcp
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
In any MCP client's server configuration:
|
|
33
|
+
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"mcpServers": {
|
|
37
|
+
"frisk": {
|
|
38
|
+
"command": "npx",
|
|
39
|
+
"args": ["-y", "frisk-mcp"]
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
No API key, no account, no network call: with no configuration the server
|
|
46
|
+
screens entirely on your machine.
|
|
47
|
+
|
|
48
|
+
## Hosted mode (optional)
|
|
49
|
+
|
|
50
|
+
Set `FRISK_API_KEY` to have the same tool answered by the hosted service, which
|
|
51
|
+
adds reputation-graph signals and returns higher-confidence verdicts:
|
|
52
|
+
|
|
53
|
+
```json
|
|
54
|
+
{
|
|
55
|
+
"mcpServers": {
|
|
56
|
+
"frisk": {
|
|
57
|
+
"command": "npx",
|
|
58
|
+
"args": ["-y", "frisk-mcp"],
|
|
59
|
+
"env": { "FRISK_API_KEY": "..." }
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
The hosted tier is in early access — email support@tryfrisk.dev. Everything
|
|
66
|
+
above works without it.
|
|
67
|
+
|
|
68
|
+
| variable | default | meaning |
|
|
69
|
+
| --- | --- | --- |
|
|
70
|
+
| `FRISK_API_KEY` | unset | Enables hosted screening. Unset means fully offline. |
|
|
71
|
+
| `FRISK_BASE_URL` | `https://api.tryfrisk.dev` | Override the hosted endpoint. |
|
|
72
|
+
|
|
73
|
+
## The tool
|
|
74
|
+
|
|
75
|
+
`screen_payment`
|
|
76
|
+
|
|
77
|
+
| argument | type | notes |
|
|
78
|
+
| --- | --- | --- |
|
|
79
|
+
| `counterparty` | string, required | The address the agent intends to pay. |
|
|
80
|
+
| `endpoint` | string | URL that quoted the payment; checked for plaintext transport. |
|
|
81
|
+
| `amount` | number | Amount about to be paid. |
|
|
82
|
+
| `asset` | string | Asset symbol, e.g. `USDC`. |
|
|
83
|
+
| `observedPayTo` | string | The `payTo` the endpoint actually returned. If it differs from `counterparty`, that is the dynamic-`payTo` swap. |
|
|
84
|
+
| `strictness` | number 0–1 | 0 permissive, 1 paranoid. Default 0.3. |
|
|
85
|
+
| `maxPerCall` | number | Spending ceiling for one call. |
|
|
86
|
+
| `allowedAssets` | string[] | Assets the agent may pay in. |
|
|
87
|
+
|
|
88
|
+
Returns `verdict`, `trustScore`, `confidence`, `reasons`, `policyHits`,
|
|
89
|
+
`source` (`lite` or `hosted`), and `allowed`.
|
|
90
|
+
|
|
91
|
+
## What it does not do
|
|
92
|
+
|
|
93
|
+
It does not detect Sybil clusters, and offline it has no view of an address's
|
|
94
|
+
history — lite screening always reports `"low"` confidence for that reason. It
|
|
95
|
+
also cannot repair the protocol underneath a payment: replay, settlement races,
|
|
96
|
+
and facilitator trust live in x402 itself, not in the request being signed.
|
|
97
|
+
Those limits are discussed in
|
|
98
|
+
[Five ways an x402 payment can go wrong](https://tryfrisk.dev/blog/screening-x402-payments).
|
|
99
|
+
|
|
100
|
+
## License
|
|
101
|
+
|
|
102
|
+
MIT
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
|
|
5
|
+
|
|
6
|
+
// src/server.ts
|
|
7
|
+
import { McpServer } from "@modelcontextprotocol/server";
|
|
8
|
+
import { Client } from "frisk-screen";
|
|
9
|
+
import { z } from "zod";
|
|
10
|
+
var inputSchema = z.object({
|
|
11
|
+
counterparty: z.string().describe("The address the agent intends to pay, e.g. an 0x EVM address."),
|
|
12
|
+
endpoint: z.string().optional().describe("URL that quoted the payment. Used to check transport safety."),
|
|
13
|
+
amount: z.number().optional().describe("Amount the agent is about to pay."),
|
|
14
|
+
asset: z.string().optional().describe("Asset symbol, e.g. USDC."),
|
|
15
|
+
observedPayTo: z.string().optional().describe(
|
|
16
|
+
"The payTo address the endpoint actually returned for this request. If it differs from the counterparty, that is the dynamic-payTo swap."
|
|
17
|
+
),
|
|
18
|
+
strictness: z.number().min(0).max(1).optional().describe("0 is permissive, 1 is paranoid. Defaults to 0.3."),
|
|
19
|
+
maxPerCall: z.number().optional().describe("Spending ceiling for a single call."),
|
|
20
|
+
allowedAssets: z.array(z.string()).optional().describe("Assets the agent is permitted to pay in.")
|
|
21
|
+
});
|
|
22
|
+
function describeResult(result) {
|
|
23
|
+
const lines = [
|
|
24
|
+
`verdict: ${result.verdict}`,
|
|
25
|
+
`trust score: ${result.trustScore}`,
|
|
26
|
+
`confidence: ${result.confidence}`,
|
|
27
|
+
`source: ${result.source}`
|
|
28
|
+
];
|
|
29
|
+
if (result.reasons.length > 0) {
|
|
30
|
+
lines.push(`reasons: ${result.reasons.join("; ")}`);
|
|
31
|
+
}
|
|
32
|
+
if (result.policyHits.length > 0) {
|
|
33
|
+
lines.push(`policy hits: ${result.policyHits.join("; ")}`);
|
|
34
|
+
}
|
|
35
|
+
return lines.join("\n");
|
|
36
|
+
}
|
|
37
|
+
function createServer(options = {}) {
|
|
38
|
+
const client = new Client({
|
|
39
|
+
apiKey: options.apiKey,
|
|
40
|
+
baseUrl: options.baseUrl
|
|
41
|
+
});
|
|
42
|
+
const server = new McpServer({
|
|
43
|
+
name: "frisk",
|
|
44
|
+
version: "0.0.1"
|
|
45
|
+
});
|
|
46
|
+
server.registerTool(
|
|
47
|
+
"screen_payment",
|
|
48
|
+
{
|
|
49
|
+
title: "Screen a payment before paying",
|
|
50
|
+
description: client.mode === "hosted" ? "Screen a counterparty an agent is about to pay. Runs the local deterministic checks and the hosted reputation graph, and returns allow / review / block with reasons. Advisory: the caller decides." : "Screen a counterparty an agent is about to pay. Runs entirely offline: address sanity, dynamic-payTo comparison, transport check, and your spending policy. Returns allow / review / block with reasons. Advisory: the caller decides. Set FRISK_API_KEY to add hosted reputation signals.",
|
|
51
|
+
inputSchema,
|
|
52
|
+
annotations: {
|
|
53
|
+
readOnlyHint: true,
|
|
54
|
+
openWorldHint: client.mode === "hosted"
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
async ({ counterparty, maxPerCall, allowedAssets, ...rest }) => {
|
|
58
|
+
const policy = maxPerCall === void 0 && allowedAssets === void 0 ? void 0 : { maxPerCall, allowedAssets };
|
|
59
|
+
try {
|
|
60
|
+
const result = await client.screen(counterparty, { ...rest, policy });
|
|
61
|
+
return {
|
|
62
|
+
content: [{ type: "text", text: describeResult(result) }],
|
|
63
|
+
structuredContent: { ...result }
|
|
64
|
+
};
|
|
65
|
+
} catch (error) {
|
|
66
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
67
|
+
return {
|
|
68
|
+
isError: true,
|
|
69
|
+
content: [
|
|
70
|
+
{
|
|
71
|
+
type: "text",
|
|
72
|
+
text: `screening failed: ${message}`
|
|
73
|
+
}
|
|
74
|
+
]
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
return server;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// src/index.ts
|
|
83
|
+
async function main() {
|
|
84
|
+
const server = createServer({
|
|
85
|
+
apiKey: process.env.FRISK_API_KEY,
|
|
86
|
+
baseUrl: process.env.FRISK_BASE_URL
|
|
87
|
+
});
|
|
88
|
+
await server.connect(new StdioServerTransport());
|
|
89
|
+
}
|
|
90
|
+
main().catch((error) => {
|
|
91
|
+
console.error(error);
|
|
92
|
+
process.exit(1);
|
|
93
|
+
});
|
|
94
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/server.ts"],"sourcesContent":["import { StdioServerTransport } from \"@modelcontextprotocol/server/stdio\";\nimport { createServer } from \"./server.js\";\n\nasync function main(): Promise<void> {\n const server = createServer({\n apiKey: process.env.FRISK_API_KEY,\n baseUrl: process.env.FRISK_BASE_URL,\n });\n await server.connect(new StdioServerTransport());\n}\n\nmain().catch((error) => {\n // stdout carries the protocol, so diagnostics go to stderr.\n console.error(error);\n process.exit(1);\n});\n","import { McpServer } from \"@modelcontextprotocol/server\";\nimport { Client, type ScreenResult } from \"frisk-screen\";\nimport { z } from \"zod\";\n\nexport interface ServerOptions {\n /** Hosted API key. Without one the server screens entirely offline. */\n apiKey?: string;\n /** Override the hosted base URL. Only used when an API key is supplied. */\n baseUrl?: string;\n}\n\nconst inputSchema = z.object({\n counterparty: z\n .string()\n .describe(\"The address the agent intends to pay, e.g. an 0x EVM address.\"),\n endpoint: z\n .string()\n .optional()\n .describe(\"URL that quoted the payment. Used to check transport safety.\"),\n amount: z.number().optional().describe(\"Amount the agent is about to pay.\"),\n asset: z.string().optional().describe(\"Asset symbol, e.g. USDC.\"),\n observedPayTo: z\n .string()\n .optional()\n .describe(\n \"The payTo address the endpoint actually returned for this request. If it differs from the counterparty, that is the dynamic-payTo swap.\",\n ),\n strictness: z\n .number()\n .min(0)\n .max(1)\n .optional()\n .describe(\"0 is permissive, 1 is paranoid. Defaults to 0.3.\"),\n maxPerCall: z\n .number()\n .optional()\n .describe(\"Spending ceiling for a single call.\"),\n allowedAssets: z\n .array(z.string())\n .optional()\n .describe(\"Assets the agent is permitted to pay in.\"),\n});\n\n/**\n * The verdict is advisory. Frisk returns a recommendation and the caller\n * decides; it never holds funds and cannot stop a payment by itself.\n */\nfunction describeResult(result: ScreenResult): string {\n const lines = [\n `verdict: ${result.verdict}`,\n `trust score: ${result.trustScore}`,\n `confidence: ${result.confidence}`,\n `source: ${result.source}`,\n ];\n if (result.reasons.length > 0) {\n lines.push(`reasons: ${result.reasons.join(\"; \")}`);\n }\n if (result.policyHits.length > 0) {\n lines.push(`policy hits: ${result.policyHits.join(\"; \")}`);\n }\n return lines.join(\"\\n\");\n}\n\n/**\n * Build the Frisk MCP server.\n *\n * One tool, deliberately. `screen_payment` is the whole deterministic floor:\n * counterparty sanity, dynamic-payTo comparison, transport check, and the\n * caller's own spending policy. With an API key the same call is answered by\n * the hosted service, which adds reputation signals.\n *\n * Note on where this belongs: an MCP tool runs when a model decides to call it,\n * so it is a weaker guarantee than calling `screen()` on the code path that\n * actually signs the payment. Use this for inspection and for agents that\n * cannot import the library; use the library where the money moves.\n */\nexport function createServer(options: ServerOptions = {}): McpServer {\n const client = new Client({\n apiKey: options.apiKey,\n baseUrl: options.baseUrl,\n });\n\n const server = new McpServer({\n name: \"frisk\",\n version: \"0.0.1\",\n });\n\n server.registerTool(\n \"screen_payment\",\n {\n title: \"Screen a payment before paying\",\n description:\n client.mode === \"hosted\"\n ? \"Screen a counterparty an agent is about to pay. Runs the local deterministic checks and the hosted reputation graph, and returns allow / review / block with reasons. Advisory: the caller decides.\"\n : \"Screen a counterparty an agent is about to pay. Runs entirely offline: address sanity, dynamic-payTo comparison, transport check, and your spending policy. Returns allow / review / block with reasons. Advisory: the caller decides. Set FRISK_API_KEY to add hosted reputation signals.\",\n inputSchema,\n annotations: {\n readOnlyHint: true,\n openWorldHint: client.mode === \"hosted\",\n },\n },\n async ({ counterparty, maxPerCall, allowedAssets, ...rest }) => {\n const policy =\n maxPerCall === undefined && allowedAssets === undefined\n ? undefined\n : { maxPerCall, allowedAssets };\n try {\n const result = await client.screen(counterparty, { ...rest, policy });\n return {\n content: [{ type: \"text\" as const, text: describeResult(result) }],\n structuredContent: { ...result },\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n isError: true,\n content: [\n {\n type: \"text\" as const,\n text: `screening failed: ${message}`,\n },\n ],\n };\n }\n },\n );\n\n return server;\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "frisk-mcp",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "MCP server for Frisk: screen an x402 payment counterparty before an agent pays.",
|
|
5
|
+
"mcpName": "dev.tryfrisk/frisk",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"frisk-mcp": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsup",
|
|
15
|
+
"test": "vitest run",
|
|
16
|
+
"typecheck": "tsc --noEmit",
|
|
17
|
+
"lint": "biome check .",
|
|
18
|
+
"format": "biome check --write .",
|
|
19
|
+
"prepublishOnly": "npm run build"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"mcp",
|
|
23
|
+
"model-context-protocol",
|
|
24
|
+
"ai-agents",
|
|
25
|
+
"x402",
|
|
26
|
+
"agent-payments",
|
|
27
|
+
"risk"
|
|
28
|
+
],
|
|
29
|
+
"license": "MIT",
|
|
30
|
+
"author": "Frisk contributors",
|
|
31
|
+
"homepage": "https://github.com/Jiangw2718i/frisk#readme",
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "git+https://github.com/Jiangw2718i/frisk.git",
|
|
35
|
+
"directory": "mcp"
|
|
36
|
+
},
|
|
37
|
+
"bugs": {
|
|
38
|
+
"url": "https://github.com/Jiangw2718i/frisk/issues"
|
|
39
|
+
},
|
|
40
|
+
"engines": {
|
|
41
|
+
"node": ">=18"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@modelcontextprotocol/server": "^2.0.0",
|
|
45
|
+
"frisk-screen": "^0.0.2",
|
|
46
|
+
"zod": "^4.2.0"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@biomejs/biome": "^2.4.16",
|
|
50
|
+
"@modelcontextprotocol/client": "^2.0.0",
|
|
51
|
+
"@types/node": "^25.9.3",
|
|
52
|
+
"tsup": "^8.5.1",
|
|
53
|
+
"typescript": "^6.0.3",
|
|
54
|
+
"vitest": "^4.1.8"
|
|
55
|
+
}
|
|
56
|
+
}
|