Skip to content

feat: add x402_fetch tool#12

Open
Intellihackz wants to merge 4 commits into
InjectiveLabs:mainfrom
Intellihackz:main
Open

feat: add x402_fetch tool#12
Intellihackz wants to merge 4 commits into
InjectiveLabs:mainfrom
Intellihackz:main

Conversation

@Intellihackz

@Intellihackz Intellihackz commented Jun 9, 2026

Copy link
Copy Markdown

Overview

This PR adds native x402 payment capabilities to the Injective MCP server, allowing AI agents to fetch gated API
endpoints and seamlessly pay the 402 Payment Required invoice using their local keystore.

Changes Made

  • Dependency Added: Installed @injectivelabs/x402 to utilize the createInjectiveClient HTTP wrapper.
  • New MCP Tool: Added the x402_fetch tool to src/mcp/server.ts.

How it Works

When an agent calls x402_fetch(address, password, url):
1. The server decrypts the local EVM private key.
2. It initiates a fetch request to the gated endpoint.
3. If the server responds with a 402 and a price quote, the client automatically signs an EIP-3009 USDC
authorization.
4. The signed payment is submitted to the x402 facilitator to settle on Injective EVM.
5. The original request is retried with the payment receipt, successfully returning the underlying data back to
the AI.

Summary by CodeRabbit

  • New Features
    • Added a new tool for accessing payment-gated web resources directly from the app.
    • The tool can automatically handle payment-required responses and retry the request after approval.
    • Responses now return the request status, destination URL, and retrieved content in a readable format.

@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@Intellihackz, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 34 minutes and 36 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2a62e314-4a60-4894-95ff-27fa5b738aec

📥 Commits

Reviewing files that changed from the base of the PR and between 3273b9d and bf79f9e.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (3)
  • README.md
  • package.json
  • src/mcp/server.ts
📝 Walkthrough

Walkthrough

A new x402_fetch MCP tool is added to src/mcp/server.ts. It unlocks an Injective wallet using a provided address and password, creates an x402 client with the resulting private key, fetches a gated URL (automatically handling 402 Payment Required via USDC signing), and returns the HTTP status, URL, and parsed response body. The @injectivelabs/x402 package is added as a dependency.

Changes

x402_fetch MCP Tool

Layer / File(s) Summary
x402_fetch tool: dependency, import, and implementation
package.json, src/mcp/server.ts
Adds @injectivelabs/x402 ^0.0.1 to dependencies, imports createInjectiveClient, and implements the x402_fetch MCP tool that unlocks a wallet keystore by address and password, instantiates an x402 client with the private key, fetches a gated URL with automatic 402 payment handling, and returns status, url, and JSON-parsed (or raw text) response data.

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant x402_fetch
  participant WalletKeystore
  participant x402Client
  participant GatedAPI

  Caller->>x402_fetch: { address, password, url }
  x402_fetch->>WalletKeystore: unlock wallet (address, password)
  WalletKeystore-->>x402_fetch: privateKey
  x402_fetch->>x402Client: createInjectiveClient(privateKey)
  x402Client-->>x402_fetch: client instance
  x402_fetch->>GatedAPI: fetch(url)
  GatedAPI-->>x402_fetch: 402 Payment Required
  x402_fetch->>GatedAPI: sign & submit USDC payment, retry
  GatedAPI-->>x402_fetch: 200 OK + body
  x402_fetch-->>Caller: { status, url, data }
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 Hoppity-hop through a paywall gate,
A wallet unlocked, no need to wait!
The x402 client signs with flair,
USDC flows right through the air.
Status 200 — the data's there! 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and concisely describes the main change: adding the x402_fetch tool.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@socket-security

socket-security Bot commented Jun 9, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​injectivelabs/​x402@​0.0.17610010091100

View full report

Comment thread src/mcp/server.ts
Comment on lines +821 to +823
address: injAddress.describe('The inj1... address of your trading wallet.'),
password: z.string().describe('Keystore password to decrypt the private key for signing.'),
url: z.string().url().describe('The URL of the x402-gated API endpoint.'),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in your PR for feat: add injective-x402-payment skill, there's meant to be "- maxAmount: (Optional) A safety limit on the maximum USDC amount you are willing to pay for this request."
see: https://github.com/InjectiveLabs/agent-skills/pull/14/changes#diff-36232111dee9b5d68812269d94f3c10a6c8b9aa93e6ecdc6b3fff44ddd1b67f8R31

but that's missing form here.

this is a feature that needs to be implemented deterministically, and therefore should be in the MCP server, not the agent skill. currently, it is implemented in neither.

Comment thread src/mcp/server.ts Outdated
import { evm } from '../evm/index.js'
import { eip712 } from '../evm/eip712.js'
import { authz, TRADING_MSG_TYPES } from '../authz/index.js'
import { createInjectiveClient } from '@injectivelabs/x402/client'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The name of this method in this context is likely to confuse.

Better import as x402CreateClient or similar.

Comment thread src/mcp/server.ts Outdated
},
async ({ address, password, url }) => {
const privateKeyHex = wallets.unlock(address, password)
const client = createInjectiveClient({ privateKey: privateKeyHex as `0x${string}` })

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for clarity: rename client -> x402Client

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

additionally, you will need to implement the maxAmount check around this point.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces an MCP tool (x402_fetch) that can call x402-gated HTTP endpoints and automatically settle 402 Payment Required invoices by signing/submitting USDC payments using a locally decrypted Injective EVM private key.

Changes:

  • Added @injectivelabs/x402 dependency to enable the x402 client wrapper.
  • Registered a new MCP tool x402_fetch in src/mcp/server.ts that performs the paid fetch flow and returns the response payload.

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 5 comments.

File Description
src/mcp/server.ts Adds the x402_fetch MCP tool and imports the x402 client wrapper.
package.json Adds the @injectivelabs/x402 dependency.
package-lock.json Locks @injectivelabs/x402@0.0.1 and its transitive dependencies/engine requirement.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/mcp/server.ts
Comment on lines +831 to +836
let data;
try {
data = JSON.parse(text)
} catch {
data = text
}
Comment thread src/mcp/server.ts
Comment on lines +826 to +830
const privateKeyHex = wallets.unlock(address, password)
const client = createInjectiveClient({ privateKey: privateKeyHex as `0x${string}` })
const response = await client.fetch(url)

const text = await response.text()
Comment thread src/mcp/server.ts
Comment on lines +816 to +820
'x402_fetch',
'Fetch data from an x402-gated API endpoint. Automatically handles 402 Payment Required ' +
'responses by signing a USDC payment using the Injective EVM wallet, submitting it to the facilitator, ' +
'and retrying the request. IMPORTANT: Real on-chain payment with real funds.',
{
Comment thread src/mcp/server.ts
Comment on lines +815 to +824
server.tool(
'x402_fetch',
'Fetch data from an x402-gated API endpoint. Automatically handles 402 Payment Required ' +
'responses by signing a USDC payment using the Injective EVM wallet, submitting it to the facilitator, ' +
'and retrying the request. IMPORTANT: Real on-chain payment with real funds.',
{
address: injAddress.describe('The inj1... address of your trading wallet.'),
password: z.string().describe('Keystore password to decrypt the private key for signing. SECURITY: Never log, store, or echo this. Use secret inputs only.'),
url: z.string().url().describe('The URL of the x402-gated API endpoint.'),
},
Comment thread package.json
"@injectivelabs/networks": "^1.14.27",
"@injectivelabs/sdk-ts": "^1.14.27",
"@injectivelabs/utils": "^1.14.27",
"@injectivelabs/x402": "^0.0.1",

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/mcp/server.ts`:
- Around line 823-828: The x402 tool handler in server.ts currently accepts any
URL via z.string().url() and passes it directly into client.fetch, which leaves
a caller-controlled fetch target. Add a pre-fetch validation step in the async
handler that restricts the URL to an HTTPS-only allowlist or equivalent approved
egress policy before calling createInjectiveClient and client.fetch, and reject
any non-HTTPS or unapproved host values with a clear error.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 32787191-431b-4e3c-99b7-3019fe312ceb

📥 Commits

Reviewing files that changed from the base of the PR and between 747441e and 3273b9d.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (2)
  • package.json
  • src/mcp/server.ts

Comment thread src/mcp/server.ts Outdated
Comment on lines +823 to +828
url: z.string().url().describe('The URL of the x402-gated API endpoint.'),
},
async ({ address, password, url }) => {
const privateKeyHex = wallets.unlock(address, password)
const client = createInjectiveClient({ privateKey: privateKeyHex as `0x${string}` })
const response = await client.fetch(url)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Constrain the fetch target before calling the x402 client.

z.string().url() still allows a caller-controlled server-side fetch target. Because Line 828 sends that URL from the MCP server, this can become SSRF and can also allow non-HTTPS payment flows unless hosts/schemes are restricted. Add an HTTPS-only allowlist or equivalent egress policy before client.fetch.

🛡️ Possible direction
+const allowedX402Hosts = new Set(
+  (process.env.X402_ALLOWED_HOSTS ?? '')
+    .split(',')
+    .map((host) => host.trim().toLowerCase())
+    .filter(Boolean),
+)
+
+const x402EndpointUrl = z.string().url().refine((value) => {
+  const parsed = new URL(value)
+  return parsed.protocol === 'https:' && allowedX402Hosts.has(parsed.hostname.toLowerCase())
+}, 'Must be an HTTPS URL on an allowed x402 host')
+
 server.tool(
@@
-    url: z.string().url().describe('The URL of the x402-gated API endpoint.'),
+    url: x402EndpointUrl.describe('The URL of the x402-gated API endpoint.'),
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
url: z.string().url().describe('The URL of the x402-gated API endpoint.'),
},
async ({ address, password, url }) => {
const privateKeyHex = wallets.unlock(address, password)
const client = createInjectiveClient({ privateKey: privateKeyHex as `0x${string}` })
const response = await client.fetch(url)
const allowedX402Hosts = new Set(
(process.env.X402_ALLOWED_HOSTS ?? '')
.split(',')
.map((host) => host.trim().toLowerCase())
.filter(Boolean),
)
const x402EndpointUrl = z.string().url().refine((value) => {
const parsed = new URL(value)
return parsed.protocol === 'https:' && allowedX402Hosts.has(parsed.hostname.toLowerCase())
}, 'Must be an HTTPS URL on an allowed x402 host')
url: x402EndpointUrl.describe('The URL of the x402-gated API endpoint.'),
async ({ address, password, url }) => {
const privateKeyHex = wallets.unlock(address, password)
const client = createInjectiveClient({ privateKey: privateKeyHex as `0x${string}` })
const response = await client.fetch(url)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/mcp/server.ts` around lines 823 - 828, The x402 tool handler in server.ts
currently accepts any URL via z.string().url() and passes it directly into
client.fetch, which leaves a caller-controlled fetch target. Add a pre-fetch
validation step in the async handler that restricts the URL to an HTTPS-only
allowlist or equivalent approved egress policy before calling
createInjectiveClient and client.fetch, and reject any non-HTTPS or unapproved
host values with a clear error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants