@agentutility/mcp-matchpoint 0.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 ADDED
@@ -0,0 +1,80 @@
1
+ # @agentutility/mcp-matchpoint
2
+
3
+ > Dedup and record linkage, per call.
4
+
5
+ Turn messy company names, people, addresses, emails, and phones into stable match keys so duplicates collide — plus a similarity score to rank candidate pairs. The dedup/entity-resolution primitives a data-enrichment agent needs.
6
+
7
+ **Pricing:** pay-per-call in USDC on Base. No subscriptions, no API keys. See per-tool prices below.
8
+
9
+ ## Install — Claude Desktop
10
+
11
+ Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
12
+
13
+ ```json
14
+ {
15
+ "mcpServers": {
16
+ "agentutility-matchpoint": {
17
+ "command": "npx",
18
+ "args": ["-y", "@agentutility/mcp-matchpoint"],
19
+ "env": { "X402_PRIVATE_KEY": "0xYOUR_PRIVATE_KEY_HEX" }
20
+ }
21
+ }
22
+ }
23
+ ```
24
+
25
+ Restart Claude Desktop. 7 tools appear in the tool palette.
26
+
27
+ ## Install — Cursor
28
+
29
+ Add to `.cursor/mcp.json`:
30
+
31
+ ```json
32
+ {
33
+ "mcpServers": {
34
+ "agentutility-matchpoint": {
35
+ "command": "npx",
36
+ "args": ["-y", "@agentutility/mcp-matchpoint"],
37
+ "env": { "X402_PRIVATE_KEY": "0x..." }
38
+ }
39
+ }
40
+ }
41
+ ```
42
+
43
+ ## Funding
44
+
45
+ Send any amount of **USDC on Base mainnet** to the address derived from your `X402_PRIVATE_KEY`. The MCP server uses it to pay for tool calls automatically.
46
+
47
+ USDC on Base contract: `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913`
48
+
49
+ ## Tools (7)
50
+
51
+ | Tool | Description |
52
+ |---|---|
53
+ | `address-parse` | (0.002 USDC/call) Address parser / parse street address into components / address splitter / USPS field extraction. Splits a freeform US address into number, street, unit, city, state, and zip. Deterministic, best-effort, no geocoding, no upstream. |
54
+ | `match-key-address` | (0.002 USDC/call) Address match key / postal address dedup / USPS-style standardization / address record linkage. Expands street types (St to Street), directionals (N to North), and unit designators (Apt/Ste/# to unit), then builds a stable key so '123 Main St Apt 4' and '123 Main Street #4' collide. Pure compute, no geocoding, no upstream. |
55
+ | `match-key-company` | (0.002 USDC/call) Company name match key / business-name dedup / entity resolution / fuzzy company matching / record linkage. Deterministic similarity key: strips legal suffixes (Inc, LLC, Corp, Ltd, GmbH), punctuation, and abbreviations, then phonetic-encodes tokens so 'IBM Corp' and 'I.B.M. Corporation, Inc.' produce the same key. Pure compute, no upstream. Use it to dedup CRM/lead lists and join company records across sources. |
56
+ | `match-key-email` | (0.002 USDC/call) Email match key / email dedup / email normalization / contact record linkage. Collapses Gmail dots and '+tag' subaddressing and lowercases the domain so 'John.Doe+promo@Gmail.com' and 'johndoe@gmail.com' share a key. Reports basic syntax validity and the domain. Pure compute, no SMTP/MX lookup, no upstream. |
57
+ | `match-key-name` | (0.002 USDC/call) Person name match key / contact dedup / people record linkage / fuzzy name matching. Canonicalizes nicknames (Bob to Robert), folds accents, drops titles/suffixes (Mr, Jr, PhD), and is order-insensitive so 'Smith, Robert' and 'Bob Smith' share a key. Returns first/last too. Pure compute, no upstream. |
58
+ | `match-key-phone` | (0.002 USDC/call) Phone match key / phone number dedup / phone normalization / E.164 formatter / contact record linkage. Strips formatting to digits and produces a canonical E.164 key so '(415) 555-0100' and '+1 415-555-0100' collide. Returns E.164, country code, and validity. Pure compute, no carrier lookup, no upstream. |
59
+ | `match-score` | (0.003 USDC/call) Fuzzy match score / string similarity / record-pair scoring / dedup confidence. Compares two values of a given type (company, name, address, email, phone, or text) and returns a 0-100 similarity score blending match-key equality, Jaro-Winkler, and token overlap, plus whether they share a match key. The companion to the match-key endpoints: bucket by key, then rank candidates by score. Pure compute, no upstream. |
60
+
61
+ ## How it works
62
+
63
+ 1. Agent calls a tool (e.g. `address-parse`).
64
+ 2. MCP server POSTs to `https://x402.agentutility.ai/address-parse`.
65
+ 3. The endpoint responds **HTTP 402** with payment instructions.
66
+ 4. The MCP server signs an EIP-3009 USDC transfer authorization with `X402_PRIVATE_KEY` and retries.
67
+ 5. CDP facilitator settles on Base.
68
+ 6. The endpoint returns the actual response.
69
+
70
+ The agent never sees the payment flow — it just gets the result.
71
+
72
+ ## Links
73
+
74
+ - Cluster overview: https://agentutility.ai/matchpoint/
75
+ - All MCP packages: https://mcp.agentutility.ai/
76
+ - Source: https://github.com/rooz21/x402/tree/main/packages/mcp-matchpoint
77
+
78
+ ---
79
+
80
+ **Version:** 0.1.0 · **License:** MIT
package/dist/index.js ADDED
@@ -0,0 +1,86 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * @agentutility/mcp-<cluster> — stdio MCP server exposing the cluster's
4
+ * x402-paid endpoints as MCP tools. Forwards every CallToolRequest to
5
+ * x402.agentutility.ai, where @x402/fetch handles 402 → payment → retry
6
+ * using the agent's own wallet (X402_PRIVATE_KEY env var).
7
+ *
8
+ * Boilerplate is single-sourced at packages/_template/src/index.ts and
9
+ * copied verbatim into each packages/mcp-<cluster>/src/index.ts by
10
+ * scripts/generate-mcp-clusters.mjs. The codegen also writes a matching
11
+ * tools.generated.ts so this file imports CLUSTER_SLUG + VERSION + TOOLS
12
+ * rather than hard-coding.
13
+ *
14
+ * Required env: X402_PRIVATE_KEY (hex EVM key, USDC on Base).
15
+ * Optional env: X402_BASE_URL (default https://x402.agentutility.ai)
16
+ * X402_RPC_URL (default https://mainnet.base.org)
17
+ */
18
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
19
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
20
+ import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
21
+ import { wrapFetchWithPayment, x402Client } from "@x402/fetch";
22
+ import { ExactEvmScheme, toClientEvmSigner } from "@x402/evm";
23
+ import { privateKeyToAccount } from "viem/accounts";
24
+ import { createPublicClient, http } from "viem";
25
+ import { base } from "viem/chains";
26
+ import { TOOLS, CLUSTER_SLUG, VERSION } from "./tools.generated.js";
27
+ const BASE_URL = (process.env.X402_BASE_URL || "https://x402.agentutility.ai").replace(/\/$/, "");
28
+ const RPC_URL = process.env.X402_RPC_URL || "https://mainnet.base.org";
29
+ const PK = process.env.X402_PRIVATE_KEY;
30
+ if (!PK) {
31
+ console.error(`[@agentutility/mcp-${CLUSTER_SLUG}] FATAL: X402_PRIVATE_KEY env var is required.`);
32
+ console.error("Set it to a hex-encoded EVM private key with USDC balance on Base (chain 8453).");
33
+ console.error("USDC on Base: 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913");
34
+ process.exit(1);
35
+ }
36
+ const account = privateKeyToAccount((PK.startsWith("0x") ? PK : `0x${PK}`));
37
+ const publicClient = createPublicClient({
38
+ chain: base,
39
+ transport: http(RPC_URL),
40
+ });
41
+ const signer = toClientEvmSigner(account, publicClient);
42
+ const client = new x402Client().register("eip155:8453", new ExactEvmScheme(signer));
43
+ const paidFetch = wrapFetchWithPayment(fetch, client);
44
+ async function trackedFetch(url, init) {
45
+ const headers = new Headers(init?.headers);
46
+ headers.set("X-Agent-Channel", `mcp-stdio-${CLUSTER_SLUG}`);
47
+ headers.set("X-Agent-Id", "47167");
48
+ if (!headers.has("User-Agent")) {
49
+ headers.set("User-Agent", `agentutility-mcp/${CLUSTER_SLUG}/${VERSION}`);
50
+ }
51
+ return paidFetch(url, { ...init, headers });
52
+ }
53
+ const server = new Server({ name: `agentutility-${CLUSTER_SLUG}`, version: VERSION }, { capabilities: { tools: {} } });
54
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({
55
+ tools: TOOLS.map((t) => ({
56
+ name: t.name,
57
+ description: t.description,
58
+ inputSchema: t.input_schema,
59
+ })),
60
+ }));
61
+ server.setRequestHandler(CallToolRequestSchema, async (req) => {
62
+ const name = req.params.name;
63
+ const tool = TOOLS.find((t) => t.name === name);
64
+ if (!tool) {
65
+ return { content: [{ type: "text", text: `Unknown tool: ${name}` }], isError: true };
66
+ }
67
+ try {
68
+ const res = await trackedFetch(`${BASE_URL}/${tool.http_name}`, {
69
+ method: "POST",
70
+ headers: { "Content-Type": "application/json" },
71
+ body: JSON.stringify(req.params.arguments ?? {}),
72
+ });
73
+ const body = await res.text();
74
+ if (!res.ok) {
75
+ return { content: [{ type: "text", text: `HTTP ${res.status}: ${body}` }], isError: true };
76
+ }
77
+ return { content: [{ type: "text", text: body }] };
78
+ }
79
+ catch (err) {
80
+ return {
81
+ content: [{ type: "text", text: `tool call failed: ${err instanceof Error ? err.message : String(err)}` }],
82
+ isError: true,
83
+ };
84
+ }
85
+ });
86
+ await server.connect(new StdioServerTransport());
@@ -0,0 +1,152 @@
1
+ /** Auto-generated by scripts/generate-mcp-clusters.mjs. Do not edit by hand. */
2
+ export const CLUSTER_SLUG = "matchpoint";
3
+ export const VERSION = "0.1.0";
4
+ export const TOOLS = [
5
+ {
6
+ "name": "address-parse",
7
+ "http_name": "address-parse",
8
+ "description": "(0.002 USDC/call) Address parser / parse street address into components / address splitter / USPS field extraction. Splits a freeform US address into number, street, unit, city, state, and zip. Deterministic, best-effort, no geocoding, no upstream.",
9
+ "method": "POST",
10
+ "input_schema": {
11
+ "type": "object",
12
+ "properties": {
13
+ "address": {
14
+ "type": "string",
15
+ "description": "Freeform US street address."
16
+ }
17
+ },
18
+ "required": [
19
+ "address"
20
+ ]
21
+ }
22
+ },
23
+ {
24
+ "name": "match-key-address",
25
+ "http_name": "match-key-address",
26
+ "description": "(0.002 USDC/call) Address match key / postal address dedup / USPS-style standardization / address record linkage. Expands street types (St to Street), directionals (N to North), and unit designators (Apt/Ste/# to unit), then builds a stable key so '123 Main St Apt 4' and '123 Main Street #4' collide. Pure compute, no geocoding, no upstream.",
27
+ "method": "POST",
28
+ "input_schema": {
29
+ "type": "object",
30
+ "properties": {
31
+ "address": {
32
+ "type": "string",
33
+ "description": "Freeform US street address."
34
+ }
35
+ },
36
+ "required": [
37
+ "address"
38
+ ]
39
+ }
40
+ },
41
+ {
42
+ "name": "match-key-company",
43
+ "http_name": "match-key-company",
44
+ "description": "(0.002 USDC/call) Company name match key / business-name dedup / entity resolution / fuzzy company matching / record linkage. Deterministic similarity key: strips legal suffixes (Inc, LLC, Corp, Ltd, GmbH), punctuation, and abbreviations, then phonetic-encodes tokens so 'IBM Corp' and 'I.B.M. Corporation, Inc.' produce the same key. Pure compute, no upstream. Use it to dedup CRM/lead lists and join company records across sources.",
45
+ "method": "POST",
46
+ "input_schema": {
47
+ "type": "object",
48
+ "properties": {
49
+ "name": {
50
+ "type": "string",
51
+ "description": "Company / organization name."
52
+ }
53
+ },
54
+ "required": [
55
+ "name"
56
+ ]
57
+ }
58
+ },
59
+ {
60
+ "name": "match-key-email",
61
+ "http_name": "match-key-email",
62
+ "description": "(0.002 USDC/call) Email match key / email dedup / email normalization / contact record linkage. Collapses Gmail dots and '+tag' subaddressing and lowercases the domain so 'John.Doe+promo@Gmail.com' and 'johndoe@gmail.com' share a key. Reports basic syntax validity and the domain. Pure compute, no SMTP/MX lookup, no upstream.",
63
+ "method": "POST",
64
+ "input_schema": {
65
+ "type": "object",
66
+ "properties": {
67
+ "email": {
68
+ "type": "string",
69
+ "description": "Email address."
70
+ }
71
+ },
72
+ "required": [
73
+ "email"
74
+ ]
75
+ }
76
+ },
77
+ {
78
+ "name": "match-key-name",
79
+ "http_name": "match-key-name",
80
+ "description": "(0.002 USDC/call) Person name match key / contact dedup / people record linkage / fuzzy name matching. Canonicalizes nicknames (Bob to Robert), folds accents, drops titles/suffixes (Mr, Jr, PhD), and is order-insensitive so 'Smith, Robert' and 'Bob Smith' share a key. Returns first/last too. Pure compute, no upstream.",
81
+ "method": "POST",
82
+ "input_schema": {
83
+ "type": "object",
84
+ "properties": {
85
+ "name": {
86
+ "type": "string",
87
+ "description": "Person full name. 'Last, First' accepted."
88
+ }
89
+ },
90
+ "required": [
91
+ "name"
92
+ ]
93
+ }
94
+ },
95
+ {
96
+ "name": "match-key-phone",
97
+ "http_name": "match-key-phone",
98
+ "description": "(0.002 USDC/call) Phone match key / phone number dedup / phone normalization / E.164 formatter / contact record linkage. Strips formatting to digits and produces a canonical E.164 key so '(415) 555-0100' and '+1 415-555-0100' collide. Returns E.164, country code, and validity. Pure compute, no carrier lookup, no upstream.",
99
+ "method": "POST",
100
+ "input_schema": {
101
+ "type": "object",
102
+ "properties": {
103
+ "phone": {
104
+ "type": "string",
105
+ "description": "Phone number in any format."
106
+ },
107
+ "region": {
108
+ "type": "string",
109
+ "description": "Default region for numbers without a country code. Default 'US'."
110
+ }
111
+ },
112
+ "required": [
113
+ "phone"
114
+ ]
115
+ }
116
+ },
117
+ {
118
+ "name": "match-score",
119
+ "http_name": "match-score",
120
+ "description": "(0.003 USDC/call) Fuzzy match score / string similarity / record-pair scoring / dedup confidence. Compares two values of a given type (company, name, address, email, phone, or text) and returns a 0-100 similarity score blending match-key equality, Jaro-Winkler, and token overlap, plus whether they share a match key. The companion to the match-key endpoints: bucket by key, then rank candidates by score. Pure compute, no upstream.",
121
+ "method": "POST",
122
+ "input_schema": {
123
+ "type": "object",
124
+ "properties": {
125
+ "a": {
126
+ "type": "string",
127
+ "description": "First value."
128
+ },
129
+ "b": {
130
+ "type": "string",
131
+ "description": "Second value."
132
+ },
133
+ "type": {
134
+ "type": "string",
135
+ "enum": [
136
+ "company",
137
+ "name",
138
+ "address",
139
+ "email",
140
+ "phone",
141
+ "text"
142
+ ],
143
+ "description": "Value type. Default 'text'."
144
+ }
145
+ },
146
+ "required": [
147
+ "a",
148
+ "b"
149
+ ]
150
+ }
151
+ }
152
+ ];
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@agentutility/mcp-matchpoint",
3
+ "version": "0.1.0",
4
+ "description": "MCP server for the @agentutility matchpoint cluster — pay-per-call x402 tools, no API keys, USDC on Base.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "dist/index.js",
8
+ "bin": {
9
+ "agentutility-mcp-matchpoint": "dist/index.js"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "README.md"
14
+ ],
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "https://github.com/rooz21/x402",
18
+ "directory": "packages/mcp-matchpoint"
19
+ },
20
+ "homepage": "https://mcp.agentutility.ai/matchpoint/",
21
+ "scripts": {
22
+ "build": "tsc",
23
+ "prepublishOnly": "npm run build"
24
+ },
25
+ "keywords": [
26
+ "mcp",
27
+ "model-context-protocol",
28
+ "x402",
29
+ "agentutility",
30
+ "agent-tools",
31
+ "matchpoint"
32
+ ],
33
+ "dependencies": {
34
+ "@modelcontextprotocol/sdk": "^1.0.4",
35
+ "@x402/fetch": "^2.12.0",
36
+ "@x402/evm": "^2.12.0",
37
+ "viem": "^2.21.0"
38
+ },
39
+ "devDependencies": {
40
+ "@types/node": "^22.0.0",
41
+ "typescript": "^5.5.0"
42
+ },
43
+ "engines": {
44
+ "node": ">=18"
45
+ }
46
+ }