@parabolicfamily/mcp 0.1.2 → 0.1.4
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 +48 -7
- package/dist/agents.d.ts +106 -0
- package/dist/agents.js +87 -0
- package/dist/agents.js.map +1 -0
- package/dist/chain.js +3 -1
- package/dist/chain.js.map +1 -1
- package/dist/coins.d.ts +1 -1
- package/dist/config.d.ts +12 -0
- package/dist/config.js +12 -5
- package/dist/config.js.map +1 -1
- package/dist/docs.js +3 -3
- package/dist/docs.js.map +1 -1
- package/dist/format.js +1 -1
- package/dist/format.js.map +1 -1
- package/dist/index.js +0 -0
- package/dist/parabolic.d.ts +102 -3
- package/dist/parabolic.js +152 -8
- package/dist/parabolic.js.map +1 -1
- package/dist/restapi.d.ts +23 -2
- package/dist/restapi.js +50 -11
- package/dist/restapi.js.map +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.js +35 -12
- package/dist/server.js.map +1 -1
- package/package.json +1 -1
- package/src/agents.ts +96 -0
- package/src/chain.ts +3 -1
- package/src/coins.ts +1 -1
- package/src/config.ts +24 -5
- package/src/docs.ts +3 -3
- package/src/format.ts +3 -1
- package/src/parabolic.ts +153 -10
- package/src/restapi.ts +51 -11
- package/src/server.ts +47 -13
package/dist/restapi.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Address } from "viem";
|
|
1
2
|
import { type CoinSummary, type StatusKey } from "./coins.js";
|
|
2
3
|
/**
|
|
3
4
|
* Parabolic's own public read API (https://www.parabolic.family/api/v1), used for listings when no
|
|
@@ -12,15 +13,35 @@ import { type CoinSummary, type StatusKey } from "./coins.js";
|
|
|
12
13
|
* Set PARABOLIC_API_URL to "" to opt out and fall back to the log scan.
|
|
13
14
|
*/
|
|
14
15
|
export type Fetch = typeof globalThis.fetch;
|
|
16
|
+
/**
|
|
17
|
+
* The `pair` filter the public API accepts (web/lib/api.ts LIST_PAIRS). "USDC" and "EURC" are the
|
|
18
|
+
* quote asset, which every source carries. "Agents" is not a property of the coin at all but of its
|
|
19
|
+
* creator, who holds an ERC-8004 identity on Arc's registry: the site resolves that in the browser
|
|
20
|
+
* after the fetch, so the JSON answers pair=Agents with an empty list. Parabolic (parabolic.ts) reads
|
|
21
|
+
* the registry itself for that one and does not send it here.
|
|
22
|
+
*/
|
|
23
|
+
export declare const PAIR_FILTERS: readonly ["USDC", "EURC", "Agents"];
|
|
24
|
+
export type PairFilter = (typeof PAIR_FILTERS)[number];
|
|
15
25
|
export declare class RestApi {
|
|
16
26
|
private readonly base;
|
|
17
27
|
private readonly chainId;
|
|
28
|
+
/** The chain's EURC address, so an EURC coin's pairToken is the real one rather than a placeholder. */
|
|
29
|
+
private readonly eurc;
|
|
18
30
|
private readonly doFetch;
|
|
19
|
-
constructor(base: string, chainId: number,
|
|
31
|
+
constructor(base: string, chainId: number,
|
|
32
|
+
/** The chain's EURC address, so an EURC coin's pairToken is the real one rather than a placeholder. */
|
|
33
|
+
eurc: Address | undefined, doFetch?: Fetch);
|
|
20
34
|
/**
|
|
21
35
|
* Returns undefined rather than throwing whenever this source cannot answer for the configured
|
|
22
36
|
* chain, so the caller can fall through to the log scan instead of failing the tool.
|
|
23
37
|
*/
|
|
24
|
-
|
|
38
|
+
/**
|
|
39
|
+
* The API sorts over its whole window (up to a thousand coins); sorting a hundred fetched rows
|
|
40
|
+
* locally would have returned the wrong top list once the board passed a hundred coins.
|
|
41
|
+
*/
|
|
42
|
+
coins(status: StatusKey | undefined, limit: number, sort?: "trending" | "new" | "near_graduation" | "market_cap", pair?: PairFilter): Promise<{
|
|
43
|
+
coins: CoinSummary[];
|
|
44
|
+
prelaunch: boolean;
|
|
45
|
+
} | undefined>;
|
|
25
46
|
private toSummary;
|
|
26
47
|
}
|
package/dist/restapi.js
CHANGED
|
@@ -1,29 +1,59 @@
|
|
|
1
|
-
import { getAddress
|
|
1
|
+
import { getAddress } from "viem";
|
|
2
2
|
import { NATIVE_QUOTE } from "./config.js";
|
|
3
3
|
import { isNative, quoteDecimalsOf } from "./coins.js";
|
|
4
|
+
/**
|
|
5
|
+
* The `pair` filter the public API accepts (web/lib/api.ts LIST_PAIRS). "USDC" and "EURC" are the
|
|
6
|
+
* quote asset, which every source carries. "Agents" is not a property of the coin at all but of its
|
|
7
|
+
* creator, who holds an ERC-8004 identity on Arc's registry: the site resolves that in the browser
|
|
8
|
+
* after the fetch, so the JSON answers pair=Agents with an empty list. Parabolic (parabolic.ts) reads
|
|
9
|
+
* the registry itself for that one and does not send it here.
|
|
10
|
+
*/
|
|
11
|
+
export const PAIR_FILTERS = ["USDC", "EURC", "Agents"];
|
|
12
|
+
/**
|
|
13
|
+
* Whole units (a JS number from the API) back to a raw integer at the quote's precision.
|
|
14
|
+
*
|
|
15
|
+
* Not `toFixed` + parseUnits: toFixed switches to exponent notation at 1e21 ("1e+22"), which
|
|
16
|
+
* parseUnits rejects, so a large enough figure would have crashed the whole listing. The API's
|
|
17
|
+
* numbers carry at most six meaningful decimals, so scale to six with float math (safe to ~9e9) and
|
|
18
|
+
* do the rest as a BigInt.
|
|
19
|
+
*/
|
|
4
20
|
const whole = (n, decimals) => {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
21
|
+
if (!Number.isFinite(n) || n < 0)
|
|
22
|
+
return 0n;
|
|
23
|
+
const micro = BigInt(Math.round(n * 1_000_000));
|
|
24
|
+
return decimals >= 6 ? micro * 10n ** BigInt(decimals - 6) : micro / 10n ** BigInt(6 - decimals);
|
|
8
25
|
};
|
|
9
26
|
export class RestApi {
|
|
10
27
|
base;
|
|
11
28
|
chainId;
|
|
29
|
+
eurc;
|
|
12
30
|
doFetch;
|
|
13
|
-
constructor(base, chainId,
|
|
31
|
+
constructor(base, chainId,
|
|
32
|
+
/** The chain's EURC address, so an EURC coin's pairToken is the real one rather than a placeholder. */
|
|
33
|
+
eurc, doFetch = globalThis.fetch) {
|
|
14
34
|
this.base = base;
|
|
15
35
|
this.chainId = chainId;
|
|
36
|
+
this.eurc = eurc;
|
|
16
37
|
this.doFetch = doFetch;
|
|
17
38
|
}
|
|
18
39
|
/**
|
|
19
40
|
* Returns undefined rather than throwing whenever this source cannot answer for the configured
|
|
20
41
|
* chain, so the caller can fall through to the log scan instead of failing the tool.
|
|
21
42
|
*/
|
|
22
|
-
|
|
43
|
+
/**
|
|
44
|
+
* The API sorts over its whole window (up to a thousand coins); sorting a hundred fetched rows
|
|
45
|
+
* locally would have returned the wrong top list once the board passed a hundred coins.
|
|
46
|
+
*/
|
|
47
|
+
async coins(status, limit, sort, pair) {
|
|
23
48
|
const url = new URL(`${this.base.replace(/\/$/, "")}/coins`);
|
|
24
49
|
url.searchParams.set("limit", String(Math.min(100, Math.max(1, limit))));
|
|
25
50
|
if (status)
|
|
26
51
|
url.searchParams.set("status", status);
|
|
52
|
+
if (pair)
|
|
53
|
+
url.searchParams.set("pair", pair);
|
|
54
|
+
const apiSort = sort === "near_graduation" ? "graduating" : sort === "market_cap" ? "mcap" : sort === "new" ? "new" : sort === "trending" ? "trending" : undefined;
|
|
55
|
+
if (apiSort)
|
|
56
|
+
url.searchParams.set("sort", apiSort);
|
|
27
57
|
let body;
|
|
28
58
|
try {
|
|
29
59
|
const res = await this.doFetch(url, { headers: { accept: "application/json", "user-agent": "parabolic-mcp" }, signal: AbortSignal.timeout(8_000) });
|
|
@@ -34,18 +64,27 @@ export class RestApi {
|
|
|
34
64
|
catch {
|
|
35
65
|
return undefined;
|
|
36
66
|
}
|
|
37
|
-
// Never present another chain's coins as this one's, and never serve the site's demo set.
|
|
67
|
+
// Never present another chain's coins as this one's, and never serve the site's demo set. And a
|
|
68
|
+
// site in pre-launch mode answers with an empty list by design, which is not the same as the chain
|
|
69
|
+
// having no coins: treat anything but a live site as "this source cannot answer" so the caller
|
|
70
|
+
// falls through to the chain rather than reporting an empty protocol.
|
|
38
71
|
if (body.meta?.chainId !== undefined && body.meta.chainId !== this.chainId)
|
|
39
72
|
return undefined;
|
|
40
73
|
if (body.meta?.mode === "sample")
|
|
41
74
|
return undefined;
|
|
42
75
|
if (!Array.isArray(body.coins))
|
|
43
76
|
return undefined;
|
|
44
|
-
|
|
77
|
+
// Pre-launch is a real answer: the site lists nothing by design until mainnet. Carrying that
|
|
78
|
+
// through lets the caller say so instead of either reporting an empty protocol as fact or
|
|
79
|
+
// falling back to a log scan that costs forty rate-limited RPC calls.
|
|
80
|
+
return { prelaunch: body.meta?.mode === "prelaunch", coins: body.coins.filter((c) => c.sample !== true && c.curve).map((c) => this.toSummary(c)) };
|
|
45
81
|
}
|
|
46
82
|
toSummary(c) {
|
|
47
|
-
|
|
48
|
-
|
|
83
|
+
// A placeholder address here went straight into list_coins output, where an agent would read it
|
|
84
|
+
// as the real EURC contract. If this chain's EURC is unknown, say so with the zero address
|
|
85
|
+
// rather than invent one; quoteDecimals is derived from the pair name, not the address.
|
|
86
|
+
const pairToken = (c.pair === "USDC" ? NATIVE_QUOTE : this.eurc ?? NATIVE_QUOTE);
|
|
87
|
+
const quoteDecimals = c.pair === "USDC" ? 18 : 6;
|
|
49
88
|
const status = c.status === "graduated" ? "graduated" : "climbing";
|
|
50
89
|
return {
|
|
51
90
|
address: getAddress(c.address), curve: getAddress(c.curve), name: c.name, ticker: c.ticker,
|
|
@@ -57,7 +96,7 @@ export class RestApi {
|
|
|
57
96
|
tradeCount: c.tradeCount ?? undefined, createdAt: c.createdAt ?? undefined, lastTradeAt: c.lastTradeAt ?? undefined,
|
|
58
97
|
graduatedAt: c.graduatedAt ?? undefined, poolId: c.poolId ?? undefined,
|
|
59
98
|
logo: c.logo ?? undefined, description: c.description ?? undefined,
|
|
60
|
-
source: "
|
|
99
|
+
source: "api",
|
|
61
100
|
};
|
|
62
101
|
}
|
|
63
102
|
}
|
package/dist/restapi.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"restapi.js","sourceRoot":"","sources":["../src/restapi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,
|
|
1
|
+
{"version":3,"file":"restapi.js","sourceRoot":"","sources":["../src/restapi.ts"],"names":[],"mappings":"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"}
|
package/dist/server.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ export declare const SERVER_INFO: {
|
|
|
9
9
|
readonly name: "parabolic";
|
|
10
10
|
readonly version: string;
|
|
11
11
|
};
|
|
12
|
-
export declare const TOOL_NAMES: readonly ["parabolic.list_coins", "parabolic.get_coin", "parabolic.quote_buy", "parabolic.quote_sell", "parabolic.build_buy_tx", "parabolic.build_sell_tx", "parabolic.build_launch_tx", "parabolic.protocol_stats", "parabolic.docs"];
|
|
12
|
+
export declare const TOOL_NAMES: readonly ["parabolic.list_coins", "parabolic.get_coin", "parabolic.quote_buy", "parabolic.quote_sell", "parabolic.build_buy_tx", "parabolic.build_sell_tx", "parabolic.build_launch_tx", "parabolic.agent_status", "parabolic.build_register_agent_tx", "parabolic.protocol_stats", "parabolic.docs"];
|
|
13
13
|
export type ServerOptions = {
|
|
14
14
|
/** Overrides applied on top of the environment-derived config. */
|
|
15
15
|
config?: Partial<Config>;
|
package/dist/server.js
CHANGED
|
@@ -4,6 +4,7 @@ import { SORT_KEYS } from "./coins.js";
|
|
|
4
4
|
import { configFromEnv } from "./config.js";
|
|
5
5
|
import { jsonText, toPlain } from "./format.js";
|
|
6
6
|
import { Parabolic } from "./parabolic.js";
|
|
7
|
+
import { PAIR_FILTERS } from "./restapi.js";
|
|
7
8
|
import { readFileSync } from "node:fs";
|
|
8
9
|
import { safeMessage } from "./format.js";
|
|
9
10
|
export { Parabolic } from "./parabolic.js";
|
|
@@ -19,6 +20,8 @@ export const TOOL_NAMES = [
|
|
|
19
20
|
"parabolic.build_buy_tx",
|
|
20
21
|
"parabolic.build_sell_tx",
|
|
21
22
|
"parabolic.build_launch_tx",
|
|
23
|
+
"parabolic.agent_status",
|
|
24
|
+
"parabolic.build_register_agent_tx",
|
|
22
25
|
"parabolic.protocol_stats",
|
|
23
26
|
"parabolic.docs",
|
|
24
27
|
];
|
|
@@ -45,39 +48,44 @@ export function createServer(opts = {}) {
|
|
|
45
48
|
const whole = z.union([z.string(), z.number()]);
|
|
46
49
|
const slippageBps = z.number().int().min(0).max(9999).optional().describe("Slippage tolerance in basis points used to derive the minimum output (default 100 = 1%)");
|
|
47
50
|
const buyer = z.string().optional().describe("Wallet that will send the buy; when given, its snipe-tax exemption is checked on the curve");
|
|
51
|
+
// Tool arguments are validated strictly: an argument the tool does not know (a misspelling, or
|
|
52
|
+
// `referral` at the top level instead of inside `memo`) is an error, not something silently dropped
|
|
53
|
+
// and quietly changing what the tool does.
|
|
54
|
+
const strictArgs = (shape) => z.object(shape).strict();
|
|
48
55
|
const readOnly = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true };
|
|
49
56
|
server.registerTool("parabolic.list_coins", {
|
|
50
57
|
title: "List Parabolic coins",
|
|
51
|
-
description: "Coins on Parabolic with status, raised / threshold / progress, price and market cap. From the subgraph when PARABOLIC_SUBGRAPH_URL is set (adds holders, 24h volume, 24h change), otherwise from a TokenLaunched log scan of the factory
|
|
52
|
-
inputSchema: {
|
|
58
|
+
description: "Coins on Parabolic with status, raised / threshold / progress, price and market cap. From the subgraph when PARABOLIC_SUBGRAPH_URL is set (adds holders, 24h volume, 24h change), otherwise from Parabolic's public read API (PARABOLIC_API_URL); a TokenLaunched log scan of the factory is the last resort when both are unavailable.",
|
|
59
|
+
inputSchema: strictArgs({
|
|
53
60
|
status: z.enum(["climbing", "graduated"]).optional().describe("climbing = still on the bonding curve; graduated = in its Uniswap v4 pool"),
|
|
54
61
|
sort: z.enum(SORT_KEYS).optional().describe("trending (24h volume, then last trade), new (launch time), near_graduation (curve progress, climbing first), market_cap"),
|
|
55
62
|
limit: z.number().int().min(1).max(100).optional().describe("Max coins to return (default 20)"),
|
|
56
|
-
|
|
63
|
+
pair: z.enum(PAIR_FILTERS).optional().describe("USDC or EURC = the coin's quote asset; Agents = coins whose creator holds an ERC-8004 identity, read from Arc's IdentityRegistry at call time whatever the listing source. A chain with no registry answers pairFilterApplied: false and says so in `source`"),
|
|
64
|
+
}),
|
|
57
65
|
annotations: readOnly,
|
|
58
66
|
}, (args) => run(() => api.listCoins(args)));
|
|
59
67
|
server.registerTool("parabolic.get_coin", {
|
|
60
68
|
title: "Get a Parabolic coin",
|
|
61
69
|
description: "Everything about one coin, read from the factory, curve and token (plus the subgraph when configured): name, ticker, creator, curve, status/phase, raised/threshold/progress, price, market cap, holders, pool id, fee terms and split, snipe-tax window and the current snipe-tax bps.",
|
|
62
|
-
inputSchema: { address },
|
|
70
|
+
inputSchema: strictArgs({ address }),
|
|
63
71
|
annotations: readOnly,
|
|
64
72
|
}, (args) => run(() => api.getCoin(args.address)));
|
|
65
73
|
server.registerTool("parabolic.quote_buy", {
|
|
66
74
|
title: "Quote a curve buy",
|
|
67
75
|
description: "Tokens received for `quoteIn` USDC (or EURC) using the curve's exact math on live reserves: fee, creator tax and snipe tax breakdown, spot vs effective price, price impact, whether the buy graduates the coin, and a suggested minTokensOut.",
|
|
68
|
-
inputSchema: { address, quoteIn: whole.describe("Quote to spend, whole units (e.g. \"50\" = 50 USDC)"), buyer, slippageBps },
|
|
76
|
+
inputSchema: strictArgs({ address, quoteIn: whole.describe("Quote to spend, whole units (e.g. \"50\" = 50 USDC)"), buyer, slippageBps }),
|
|
69
77
|
annotations: readOnly,
|
|
70
78
|
}, (args) => run(() => api.quoteBuy(args)));
|
|
71
79
|
server.registerTool("parabolic.quote_sell", {
|
|
72
80
|
title: "Quote a curve sell",
|
|
73
81
|
description: "Quote received for `tokensIn` coins using the curve's exact math on live reserves: gross, fee and creator tax, effective price, price impact and a suggested minQuoteOut. Sells carry no snipe tax.",
|
|
74
|
-
inputSchema: { address, tokensIn: whole.describe("Coins to sell, whole tokens (e.g. \"1000000\")"), slippageBps },
|
|
82
|
+
inputSchema: strictArgs({ address, tokensIn: whole.describe("Coins to sell, whole tokens (e.g. \"1000000\")"), slippageBps }),
|
|
75
83
|
annotations: readOnly,
|
|
76
84
|
}, (args) => run(() => api.quoteSell(args)));
|
|
77
85
|
server.registerTool("parabolic.build_buy_tx", {
|
|
78
86
|
title: "Build an unsigned buy",
|
|
79
87
|
description: "Unsigned `curve.buy(quoteIn, minTokensOut, recipient)` as { to, data, value, chainId } for the caller's wallet to sign. Native-USDC curves take the quote as value; EURC curves return an approval step too. Pass `memo` for the memo-routed variant (referral code in an Arc memo; EOA-only).",
|
|
80
|
-
inputSchema: {
|
|
88
|
+
inputSchema: strictArgs({
|
|
81
89
|
address,
|
|
82
90
|
quoteIn: whole.describe("Quote to spend, whole units"),
|
|
83
91
|
minTokensOut: whole.optional().describe("Minimum coins to receive, whole tokens; derived from the live quote and slippageBps when omitted"),
|
|
@@ -85,25 +93,25 @@ export function createServer(opts = {}) {
|
|
|
85
93
|
buyer,
|
|
86
94
|
slippageBps,
|
|
87
95
|
memo: z.object({ referral: z.string().optional().describe("Referrer's 16-hex referral code or wallet address"), note: z.string().max(280).optional() }).optional().describe("Route through ParabolicMemoRouter via Arc's Memo contract (EOA-only, needs PARABOLIC_MEMO_ROUTER)"),
|
|
88
|
-
},
|
|
96
|
+
}),
|
|
89
97
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: false, openWorldHint: true },
|
|
90
98
|
}, (args) => run(() => api.buildBuyTx(args)));
|
|
91
99
|
server.registerTool("parabolic.build_sell_tx", {
|
|
92
100
|
title: "Build an unsigned sell",
|
|
93
101
|
description: "Unsigned ERC-20 approval plus `curve.sell(tokensIn, minQuoteOut, recipient)` as { to, data, value, chainId } for the caller's wallet to sign.",
|
|
94
|
-
inputSchema: {
|
|
102
|
+
inputSchema: strictArgs({
|
|
95
103
|
address,
|
|
96
104
|
tokensIn: whole.describe("Coins to sell, whole tokens"),
|
|
97
105
|
minQuoteOut: whole.optional().describe("Minimum quote to receive, whole units; derived from the live quote and slippageBps when omitted"),
|
|
98
106
|
recipient: z.string().describe("Address that receives the quote (normally the signer)"),
|
|
99
107
|
slippageBps,
|
|
100
|
-
},
|
|
108
|
+
}),
|
|
101
109
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: false, openWorldHint: true },
|
|
102
110
|
}, (args) => run(() => api.buildSellTx(args)));
|
|
103
111
|
server.registerTool("parabolic.build_launch_tx", {
|
|
104
112
|
title: "Build an unsigned launch",
|
|
105
113
|
description: "Unsigned `factory.launchToken(TokenParams, launchConfigId, pairToken)` with the launch fee as value, using the same TokenParams shape as the web Create form (expectedEconomics pinned from the factory, random salt). Optional devBuy returns the follow-up buy calldata for the creator to send once the curve address is known.",
|
|
106
|
-
inputSchema: {
|
|
114
|
+
inputSchema: strictArgs({
|
|
107
115
|
name: z.string().min(1).max(64),
|
|
108
116
|
ticker: z.string().min(1).max(16).describe("Symbol, letters and digits"),
|
|
109
117
|
image: z.string().max(512).optional().describe("https:// or ipfs:// pointer to a square image"),
|
|
@@ -114,9 +122,24 @@ export function createServer(opts = {}) {
|
|
|
114
122
|
creatorTaxBps: z.number().int().min(0).max(1000).optional().describe("Creator tax in basis points, 0–500 (5%) on the adopted parameters"),
|
|
115
123
|
creator: z.string().describe("Wallet that signs the launch; becomes deployer and creatorFeeRecipient"),
|
|
116
124
|
buybackEnabled: z.boolean().optional().describe("Default true"),
|
|
117
|
-
},
|
|
125
|
+
}),
|
|
118
126
|
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: false, openWorldHint: true },
|
|
119
127
|
}, (args) => run(() => api.buildLaunchTx(args)));
|
|
128
|
+
server.registerTool("parabolic.agent_status", {
|
|
129
|
+
title: "Agent identity status",
|
|
130
|
+
description: "Whether a wallet holds an ERC-8004 agent identity on Arc: balanceOf on the IdentityRegistry Arc runs, how many identities the wallet holds, and the registry address and chain. Arc has published a registry for Arc Testnet only, so on a chain without one the tool says that instead of answering registered or not.",
|
|
131
|
+
inputSchema: strictArgs({ address: z.string().describe("Wallet to check (0x…)") }),
|
|
132
|
+
annotations: readOnly,
|
|
133
|
+
}, (args) => run(() => api.agentStatus(args)));
|
|
134
|
+
server.registerTool("parabolic.build_register_agent_tx", {
|
|
135
|
+
title: "Build an unsigned agent registration",
|
|
136
|
+
description: "Unsigned `register(metadataURI)` on Arc's ERC-8004 IdentityRegistry as { to, data, value, chainId } for the caller's own wallet to sign. It mints an ERC-721 identity to the signer and returns the agent id. metadataURI is a pointer to the agent's metadata (an https:// or ipfs:// URL) stored as the token's tokenURI; it may be empty, and identities on Arc Testnet exist with no URI. The registry is Arc's, not Parabolic's.",
|
|
137
|
+
inputSchema: strictArgs({
|
|
138
|
+
from: z.string().describe("Wallet that signs and receives the identity (the registry mints to msg.sender)"),
|
|
139
|
+
metadataURI: z.string().max(512).optional().describe("Pointer to the agent's metadata, stored as tokenURI; empty when omitted"),
|
|
140
|
+
}),
|
|
141
|
+
annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: false, openWorldHint: true },
|
|
142
|
+
}, (args) => run(() => api.buildRegisterAgentTx(args)));
|
|
120
143
|
server.registerTool("parabolic.protocol_stats", {
|
|
121
144
|
title: "Protocol stats",
|
|
122
145
|
description: "Launches, graduations, trades, volume and fees from the subgraph (with a daily series), plus the factory's live launch fee, curve preset, snipe-tax terms and contract addresses.",
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AACtF,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,aAAa,EAAe,MAAM,aAAa,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parabolicfamily/mcp",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "MCP server for Parabolic, the dollar-native token launchpad on Arc: discover coins, quote curve trades and build unsigned transactions. Never holds keys.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
package/src/agents.ts
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { encodeFunctionData, parseAbi, toHex, type Address } from "viem";
|
|
2
|
+
import { mapLimit, type Rpc } from "./chain.js";
|
|
3
|
+
import { addrOf, big, str } from "./format.js";
|
|
4
|
+
import type { UnsignedTx } from "./tx.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* ERC-8004 agent identity on Arc.
|
|
8
|
+
*
|
|
9
|
+
* The registries are Arc's, not Parabolic's: Arc deploys them and documents them
|
|
10
|
+
* (https://docs.arc.io/arc/tutorials/register-your-first-ai-agent.md, which registers an agent with
|
|
11
|
+
* `register(string metadataURI)`). The IdentityRegistry is an ERC-1967 proxy, so Arc can change the
|
|
12
|
+
* implementation behind the address in DEPLOYMENTS without the address moving, and the facts recorded
|
|
13
|
+
* below hold for the implementation that answered on the date given.
|
|
14
|
+
*
|
|
15
|
+
* Verified against https://rpc.testnet.arc.io on 13 September 2026: name() = "AgentIdentity",
|
|
16
|
+
* symbol() = "AGENT", supportsInterface(0x80ac58cd) and (0x5b5e139f) true (ERC-721 and Metadata),
|
|
17
|
+
* balanceOf / ownerOf / tokenURI answer, and register(string) is in the implementation bytecode with
|
|
18
|
+
* selector 0xf2c298be.
|
|
19
|
+
*
|
|
20
|
+
* There is deliberately no "list this wallet's agent ids" function. supportsInterface(0x780e9d63) is
|
|
21
|
+
* false: the registry is not ERC-721 Enumerable and has neither totalSupply nor tokenOfOwnerByIndex,
|
|
22
|
+
* so the ids could only come from a Transfer log scan. Public Arc RPCs cap eth_getLogs near 10,000
|
|
23
|
+
* blocks and rate-limit the walk, which is the same cost that moved coin listing off the chain and
|
|
24
|
+
* onto an indexer. balanceOf answers the question the tools actually ask in one eth_call.
|
|
25
|
+
*/
|
|
26
|
+
export const identityRegistryAbi = parseAbi([
|
|
27
|
+
"function register(string metadataURI) returns (uint256 agentId)",
|
|
28
|
+
"function balanceOf(address owner) view returns (uint256)",
|
|
29
|
+
"function ownerOf(uint256 tokenId) view returns (address)",
|
|
30
|
+
"function tokenURI(uint256 tokenId) view returns (string)",
|
|
31
|
+
]);
|
|
32
|
+
|
|
33
|
+
/** Longest metadata URI this server encodes; a pointer, not a document. */
|
|
34
|
+
export const MAX_METADATA_URI_BYTES = 512;
|
|
35
|
+
|
|
36
|
+
export type AgentStatus = { address: Address; registered: boolean; identities: number };
|
|
37
|
+
|
|
38
|
+
/** `balanceOf(owner)`: whether the wallet holds an agent identity, and how many it holds. */
|
|
39
|
+
export async function readAgentStatus(rpc: Rpc, registry: Address, owner: Address): Promise<AgentStatus> {
|
|
40
|
+
const balance = big(await rpc.read({ address: registry, abi: identityRegistryAbi, functionName: "balanceOf", args: [owner] }));
|
|
41
|
+
return { address: owner, registered: balance > 0n, identities: Number(balance) };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Most wallets one listing checks against the registry: one eth_call each, batched by the transport. */
|
|
45
|
+
export const AGENT_LOOKUP_MAX = 100;
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Which of these wallets hold an identity, as a set of lowercase addresses. This is how a coin list is
|
|
49
|
+
* filtered to agent launches: the flag is a property of the creator, not of the coin, so it is read
|
|
50
|
+
* per creator at call time.
|
|
51
|
+
*
|
|
52
|
+
* A read that fails is counted, not guessed: "the registry did not answer" is not "this wallet holds
|
|
53
|
+
* none", and the caller has to be able to say how many creators went unchecked.
|
|
54
|
+
*/
|
|
55
|
+
export async function readAgentOwners(rpc: Rpc, registry: Address, owners: readonly Address[]): Promise<{ agents: Set<string>; checked: number; failed: number }> {
|
|
56
|
+
const unique = [...new Set(owners.map((o) => o.toLowerCase()))].slice(0, AGENT_LOOKUP_MAX);
|
|
57
|
+
const agents = new Set<string>();
|
|
58
|
+
let failed = 0;
|
|
59
|
+
await mapLimit(unique, 8, async (owner) => {
|
|
60
|
+
try {
|
|
61
|
+
const balance = big(await rpc.read({ address: registry, abi: identityRegistryAbi, functionName: "balanceOf", args: [owner as Address] }));
|
|
62
|
+
if (balance > 0n) agents.add(owner);
|
|
63
|
+
} catch {
|
|
64
|
+
failed += 1;
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
return { agents, checked: unique.length, failed };
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export type AgentIdentity = { agentId: string; owner: Address; metadataURI: string };
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* One identity by agent id: the ERC-721 tokenId that `register` returns, also readable from the
|
|
74
|
+
* Transfer log in the registration receipt. The metadata URI comes back empty for an identity
|
|
75
|
+
* registered without one, which is common on Arc Testnet (tokenURI(1) is the empty string).
|
|
76
|
+
*/
|
|
77
|
+
export async function readAgent(rpc: Rpc, registry: Address, agentId: bigint): Promise<AgentIdentity> {
|
|
78
|
+
const [owner, uri] = await Promise.all([
|
|
79
|
+
rpc.read({ address: registry, abi: identityRegistryAbi, functionName: "ownerOf", args: [agentId] }),
|
|
80
|
+
rpc.read({ address: registry, abi: identityRegistryAbi, functionName: "tokenURI", args: [agentId] }),
|
|
81
|
+
]);
|
|
82
|
+
return { agentId: agentId.toString(), owner: addrOf(owner), metadataURI: str(uri) };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/** `registry.register(metadataURI)`: mints an identity to whoever signs and returns its agent id. Carries no value. */
|
|
86
|
+
export function encodeRegisterAgent(registry: Address, metadataURI: string, chainId: number): UnsignedTx {
|
|
87
|
+
const data = encodeFunctionData({ abi: identityRegistryAbi, functionName: "register", args: [metadataURI] });
|
|
88
|
+
return {
|
|
89
|
+
to: registry,
|
|
90
|
+
data,
|
|
91
|
+
value: toHex(0n),
|
|
92
|
+
valueWei: "0",
|
|
93
|
+
chainId,
|
|
94
|
+
description: `ERC-8004 IdentityRegistry.register(metadataURI=${metadataURI === "" ? "(empty)" : metadataURI}): mints an agent identity to the wallet that signs`,
|
|
95
|
+
};
|
|
96
|
+
}
|
package/src/chain.ts
CHANGED
|
@@ -41,7 +41,9 @@ export function viemRpc(rpcUrl: string, chainId: number): Rpc {
|
|
|
41
41
|
logIndex: l.logIndex ?? 0,
|
|
42
42
|
}));
|
|
43
43
|
},
|
|
44
|
-
|
|
44
|
+
// viem caches the block number for four seconds by default; the log scan uses it as the top of
|
|
45
|
+
// its newest window, so a coin launched in that window was missed. Always read the real head.
|
|
46
|
+
blockNumber: () => client.getBlockNumber({ cacheTime: 0 }),
|
|
45
47
|
};
|
|
46
48
|
}
|
|
47
49
|
|
package/src/coins.ts
CHANGED
|
@@ -37,7 +37,7 @@ export type CoinSummary = {
|
|
|
37
37
|
logo?: string;
|
|
38
38
|
description?: string;
|
|
39
39
|
launchConfigId?: number;
|
|
40
|
-
source: "subgraph" | "chain";
|
|
40
|
+
source: "subgraph" | "api" | "chain";
|
|
41
41
|
};
|
|
42
42
|
|
|
43
43
|
export const isNative = (pairToken: string): boolean => pairToken.toLowerCase() === NATIVE_QUOTE;
|
package/src/config.ts
CHANGED
|
@@ -26,16 +26,27 @@ export const DEPLOYMENTS: Record<number, {
|
|
|
26
26
|
eurc?: Address;
|
|
27
27
|
/** Deployment block. The no-subgraph listing scans TokenLaunched from here; a public RPC refuses a scan from 0. */
|
|
28
28
|
startBlock?: number;
|
|
29
|
+
/** The site API that serves this deployment. Production serves mainnet; the testnet site serves the testnet factory. */
|
|
30
|
+
apiUrl?: string;
|
|
31
|
+
/**
|
|
32
|
+
* Arc's ERC-8004 IdentityRegistry, not one of ours. It is an ERC-1967 proxy, so Arc can upgrade the
|
|
33
|
+
* implementation behind this address at any time. Arc publishes one for Arc Testnet only, so a chain
|
|
34
|
+
* without an entry here has no registry to read rather than a missing configuration.
|
|
35
|
+
*/
|
|
36
|
+
agentRegistry?: Address;
|
|
29
37
|
}> = {
|
|
30
38
|
5042002: {
|
|
31
39
|
rpcUrl: "https://rpc.testnet.arc.io",
|
|
32
|
-
factory: "
|
|
33
|
-
memoRouter: "
|
|
40
|
+
factory: "0x2E06eD99bD7D164458847D186B282B23700b2C63",
|
|
41
|
+
memoRouter: "0x1381567ea31a094e64f6B39Bd880d0b59c48e08F",
|
|
34
42
|
eurc: "0x89B50855Aa3bE2F677cD6303Cec089B5F319D72a",
|
|
35
|
-
startBlock:
|
|
43
|
+
startBlock: 61736670,
|
|
44
|
+
apiUrl: "https://parabolic-testnet.vercel.app/api/v1",
|
|
45
|
+
agentRegistry: "0x8004A818BFB912233c491871b3d84c89A494BD9e",
|
|
36
46
|
},
|
|
37
47
|
5042: {
|
|
38
48
|
rpcUrl: "https://rpc.arc.io",
|
|
49
|
+
apiUrl: DEFAULT_API_URL,
|
|
39
50
|
},
|
|
40
51
|
};
|
|
41
52
|
|
|
@@ -44,6 +55,8 @@ export const DEFAULT_RPC_URL = DEPLOYMENTS[DEFAULT_CHAIN_ID].rpcUrl;
|
|
|
44
55
|
export type Config = {
|
|
45
56
|
/** JSON-RPC endpoint for Arc. */
|
|
46
57
|
rpcUrl: string;
|
|
58
|
+
/** PARABOLIC_RPC_URL was set to something other than the deployment's own endpoint (a fork, a private node). */
|
|
59
|
+
rpcOverridden?: boolean;
|
|
47
60
|
/** 5042002 = Arc Testnet, 5042 = Arc mainnet (id unofficial until Circle publishes it). */
|
|
48
61
|
chainId: number;
|
|
49
62
|
/** ParabolicLaunchFactory. Required for on-chain coin lookups and for building launch transactions. */
|
|
@@ -63,6 +76,8 @@ export type Config = {
|
|
|
63
76
|
hook?: Address;
|
|
64
77
|
/** Arc's Memo system contract. */
|
|
65
78
|
arcMemo: Address;
|
|
79
|
+
/** Arc's ERC-8004 IdentityRegistry. Optional; undefined on a chain where Arc has published none. */
|
|
80
|
+
agentRegistry?: Address;
|
|
66
81
|
/** Launch config index on the factory; preset 0 is the adopted $5K / $12,500 curve. */
|
|
67
82
|
launchConfigId: bigint;
|
|
68
83
|
/** First block to scan for `TokenLaunched` logs when listing without a subgraph. */
|
|
@@ -78,8 +93,9 @@ export const ENV_VARS: Array<[name: string, meaning: string]> = [
|
|
|
78
93
|
["PARABOLIC_SUBGRAPH_URL", "Parabolic subgraph endpoint (listing, holders, volume, protocol stats)"],
|
|
79
94
|
["PARABOLIC_EURC", "ERC-20 EURC address (EURC-quoted launches only)"],
|
|
80
95
|
["PARABOLIC_HOOK", "ParabolicHook address (optional; read from the factory when unset)"],
|
|
81
|
-
["PARABOLIC_API_URL", `Parabolic public read API for listings (default ${DEFAULT_API_URL}; "" to use a log scan instead)`],
|
|
96
|
+
["PARABOLIC_API_URL", `Parabolic public read API for listings (default: the site that serves the chain's deployment, ${DEPLOYMENTS[DEFAULT_CHAIN_ID].apiUrl} on Arc Testnet, ${DEFAULT_API_URL} on Arc; "" to use a log scan instead)`],
|
|
82
97
|
["PARABOLIC_ARC_MEMO", `Arc Memo system contract (default ${ARC_MEMO_DEFAULT})`],
|
|
98
|
+
["PARABOLIC_AGENT_REGISTRY", `Arc's ERC-8004 IdentityRegistry (agent_status, build_register_agent_tx and the list_coins pair "Agents" filter; default ${DEPLOYMENTS[DEFAULT_CHAIN_ID].agentRegistry} on Arc Testnet, none published for Arc yet)`],
|
|
83
99
|
["PARABOLIC_LAUNCH_CONFIG_ID", "factory launch config index (default 0)"],
|
|
84
100
|
["PARABOLIC_FACTORY_START_BLOCK", "first block for the TokenLaunched log scan (default: the factory's deployment block for this chain)"],
|
|
85
101
|
];
|
|
@@ -106,14 +122,17 @@ export function configFromEnv(env: Record<string, string | undefined> = process.
|
|
|
106
122
|
const known = DEPLOYMENTS[chainId];
|
|
107
123
|
return {
|
|
108
124
|
rpcUrl: env.PARABOLIC_RPC_URL?.trim() || known?.rpcUrl || DEFAULT_RPC_URL,
|
|
125
|
+
// A different endpoint than the deployment's may be a fork or a private node with other state.
|
|
126
|
+
rpcOverridden: Boolean(env.PARABOLIC_RPC_URL?.trim()) && env.PARABOLIC_RPC_URL!.trim() !== known?.rpcUrl,
|
|
109
127
|
chainId,
|
|
110
128
|
factory: addr("PARABOLIC_FACTORY", env.PARABOLIC_FACTORY) ?? known?.factory,
|
|
111
129
|
memoRouter: addr("PARABOLIC_MEMO_ROUTER", env.PARABOLIC_MEMO_ROUTER) ?? known?.memoRouter,
|
|
112
|
-
apiUrl: env.PARABOLIC_API_URL === undefined ? DEFAULT_API_URL : env.PARABOLIC_API_URL.trim() || undefined,
|
|
130
|
+
apiUrl: env.PARABOLIC_API_URL === undefined ? known?.apiUrl ?? DEFAULT_API_URL : env.PARABOLIC_API_URL.trim() || undefined,
|
|
113
131
|
subgraphUrl: env.PARABOLIC_SUBGRAPH_URL?.trim() || undefined,
|
|
114
132
|
eurc: addr("PARABOLIC_EURC", env.PARABOLIC_EURC) ?? known?.eurc,
|
|
115
133
|
hook: addr("PARABOLIC_HOOK", env.PARABOLIC_HOOK),
|
|
116
134
|
arcMemo: addr("PARABOLIC_ARC_MEMO", env.PARABOLIC_ARC_MEMO) ?? ARC_MEMO_DEFAULT,
|
|
135
|
+
agentRegistry: addr("PARABOLIC_AGENT_REGISTRY", env.PARABOLIC_AGENT_REGISTRY) ?? known?.agentRegistry,
|
|
117
136
|
launchConfigId: BigInt(int("PARABOLIC_LAUNCH_CONFIG_ID", env.PARABOLIC_LAUNCH_CONFIG_ID, 0)),
|
|
118
137
|
factoryStartBlock: BigInt(int("PARABOLIC_FACTORY_START_BLOCK", env.PARABOLIC_FACTORY_START_BLOCK, known?.startBlock ?? 0)),
|
|
119
138
|
};
|
package/src/docs.ts
CHANGED
|
@@ -19,7 +19,7 @@ export function docsText(config: Config): string {
|
|
|
19
19
|
"- Trade fee: 1.00% (100 bps) on the quote leg, before and after graduation (ParabolicHook takes it on the pool). Split: creator 50 / protocol 30 / buyback vault 20 (vault vests 5 years). On-chain: protocolFeeShareBps of the fee goes to protocol; buybackBurnBps of the remaining creator slice goes to the buyback.",
|
|
20
20
|
"- Creator tax: optional 0–5% (0–500 bps), fixed at launch, charged like the fee on buys and sells, paid entirely to the creator.",
|
|
21
21
|
"- Snipe tax: 93% (9,300 bps) at launch decaying to 0 over 5 s along a quadratic ease-out (remaining² / window²); capped at 10,000 − fee − creatorTax − 1 bps, which 9,300 stays below at every legal creator tax, so it is charged as written. Buys only. Only the deployer is exempt, for the buy in their own launch; there is no other exemption pathway. Snipe revenue is split like the base fee.",
|
|
22
|
-
"- Referral: a bytes8 referral code (first 8 bytes of the referrer's address) carried in the Arc memo of a routed buy earns 10% of the
|
|
22
|
+
"- Referral: a bytes8 referral code (first 8 bytes of the referrer's address) carried in the Arc memo of a routed buy earns 10% of the fee.",
|
|
23
23
|
"- Dev buy (fair launch): the creator's opening buy is snipe-tax exempt. ParabolicMemoRouter.launchAndBuy (native USDC; value = launch fee + buy) and launchAndBuyWithToken (ERC-20 quote; value = launch fee, buy pulled after an approval) place it inside the launch transaction, before anyone else can trade. The router forwards no exemption list and requires creatorFeeRecipient to be zero or the signer (FeeRecipientMustBeCreator); buyQuoteIn must be non-zero (ZeroBuyAmount). Without the router the buy is a second transaction to the new curve right after launch.",
|
|
24
24
|
"",
|
|
25
25
|
"CURVE MECHANICS (what the tools compute)",
|
|
@@ -41,10 +41,10 @@ export function docsText(config: Config): string {
|
|
|
41
41
|
"THIS SERVER",
|
|
42
42
|
`- Chain: ${chainName(config.chainId)} (${config.chainId}), RPC ${endpointHost(config.rpcUrl)}.`,
|
|
43
43
|
`- Factory: ${set(config.factory)} · Memo router: ${set(config.memoRouter)} · Subgraph: ${config.subgraphUrl ? endpointHost(config.subgraphUrl) : "(not configured)"} · EURC: ${set(config.eurc)} · Hook: ${config.hook ?? "(read from factory)"} · Launch config id: ${config.launchConfigId}.`,
|
|
44
|
-
"- Tools: parabolic.list_coins, parabolic.get_coin, parabolic.quote_buy, parabolic.quote_sell, parabolic.build_buy_tx, parabolic.build_sell_tx, parabolic.build_launch_tx, parabolic.protocol_stats, parabolic.docs. Resources: parabolic://docs/parameters, parabolic://coins/{address}.",
|
|
44
|
+
"- Tools: parabolic.list_coins, parabolic.get_coin, parabolic.quote_buy, parabolic.quote_sell, parabolic.build_buy_tx, parabolic.build_sell_tx, parabolic.build_launch_tx, parabolic.protocol_stats, parabolic.agent_status, parabolic.build_register_agent_tx, parabolic.docs. Resources: parabolic://docs/parameters, parabolic://coins/{address}.",
|
|
45
45
|
"- It never holds keys, signs, sends or broadcasts. build_* tools return unsigned { to, data, value, chainId } for the caller's wallet. Quotes are read from chain at call time and can move before a transaction lands.",
|
|
46
46
|
`- build_launch_tx: with PARABOLIC_MEMO_ROUTER set and devBuy > 0 it returns one ParabolicMemoRouter.launchAndBuy transaction (creatorFeeRecipient zero, minTokensOut from the curve math on the launch config's phantom quote, value = launch fee + devBuy)${config.memoRouter ? " (router configured)" : " (router not configured here)"}; otherwise factory.launchToken plus, for a devBuy, the two-step plan (buy calldata to send to the new curve).`,
|
|
47
|
-
"- The factory ABI has no enumeration function; listing uses the subgraph,
|
|
47
|
+
"- The factory ABI has no enumeration function; listing uses the subgraph when set, otherwise Parabolic's public read API (PARABOLIC_API_URL), and a TokenLaunched log scan of the factory only when both are unavailable.",
|
|
48
48
|
"",
|
|
49
49
|
"ENVIRONMENT",
|
|
50
50
|
...ENV_VARS.map(([k, v]) => `- ${k}: ${v}`),
|
package/src/format.ts
CHANGED
|
@@ -62,7 +62,9 @@ export function safeMessage(e: unknown): string {
|
|
|
62
62
|
// the cause, so a rate limit surfaced as "Request exceeds defined limit" with no way to tell why.
|
|
63
63
|
const headline = lines[0] ?? "Request failed";
|
|
64
64
|
// Keep the diagnostic lines and drop the ones that carry the endpoint or the request body.
|
|
65
|
-
const diagnostics = lines.slice(1).filter((l) =>
|
|
65
|
+
const diagnostics = lines.slice(1).filter((l, i, all) =>
|
|
66
|
+
/^(Status|Details|Code|Error|Reason):/.test(l) || (i === 0 && /:$/.test(all[0] ?? "") && !/^(URL|Request body|Version):/.test(l)),
|
|
67
|
+
);
|
|
66
68
|
const kept = [headline, ...diagnostics].join(" ");
|
|
67
69
|
return `${kept.replace(/https?:\/\/[^\s"']+/g, "<endpoint>")} (endpoint masked)`;
|
|
68
70
|
}
|