Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/mcp-docs-reconcile.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"nansen-cli": patch
---

Add a canonical MCP setup section to the README — endpoint `https://mcp.nansen.ai/ra/mcp`, `NANSEN-API-KEY` auth, and one-click / one-command / manual paths for Claude Desktop, Claude Code, Cursor, Claude Tag, and generic or stdio-only clients — and point the credit top-up warnings at the canonical API-key URL (app.nansen.ai/auth/agent-setup).
57 changes: 56 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,61 @@ nansen schema [command] [--pretty] # full command reference (no API key neede

Run `nansen schema --pretty` for the full subcommand and field reference.

## MCP

Connect any MCP client to Nansen's streamable HTTP server:

- **Endpoint:** `https://mcp.nansen.ai/ra/mcp`
- **Authentication:** `NANSEN-API-KEY` header
- **API key:** [app.nansen.ai/auth/agent-setup](https://app.nansen.ai/auth/agent-setup)

**One-click:** [Claude Desktop (`.dxt` bundle)](https://docs.nansen.ai/mcp/connecting) and [Cursor (install deep link)](https://docs.nansen.ai/mcp/connecting) are available from the connection docs.

**One-command (Claude Code):**

```bash
claude mcp add --transport http nansen https://mcp.nansen.ai/ra/mcp --header "NANSEN-API-KEY: <your-key>"
```

**Manual (any streamable-HTTP client):** for example, add this to Cursor's `~/.cursor/mcp.json`:

```json
{
"mcpServers": {
"nansen": {
"url": "https://mcp.nansen.ai/ra/mcp",
"headers": {
"NANSEN-API-KEY": "<your-key>"
}
}
}
}
```

**Manual (stdio-only clients):** use `mcp-remote` as a bridge. Keep the header as one argument with no space after the colon:

```json
{
"mcpServers": {
"nansen": {
"command": "npx",
"args": [
"-y",
"mcp-remote@latest",
"https://mcp.nansen.ai/ra/mcp",
"--header",
"NANSEN-API-KEY:${NANSEN_API_KEY}"
],
"env": {
"NANSEN_API_KEY": "<your-key>"
}
}
}
}
```

**Claude Tag (Claude in Slack):** an admin must attach a plugin whose `.mcp.json` points at `https://mcp.nansen.ai/ra/mcp` and add a custom credential allowing the host `mcp.nansen.ai`. See the [Claude Tag custom-connections documentation](https://claude.com/docs/claude-tag/admins/connections/custom). Per-user fallback: use Claude Code or Claude Desktop.

## Trading

DEX swaps on `solana` and `base`. Two-step: quote then execute.
Expand Down Expand Up @@ -216,7 +271,7 @@ nansen research smart-money netflow --chain solana --fields token_symbol,net_flo

| Code | Action |
|------|--------|
| `CREDITS_EXHAUSTED` | Stop all API calls immediately. `details.credits.remaining` is your actual balance. Top up at [app.nansen.ai/api](https://app.nansen.ai/api). |
| `CREDITS_EXHAUSTED` | Stop all API calls immediately. `details.credits.remaining` is your actual balance. Top up at [app.nansen.ai/auth/agent-setup](https://app.nansen.ai/auth/agent-setup). |
| `UNAUTHORIZED` | Wrong or missing key. Re-auth. |
| `RATE_LIMITED` | Auto-retried by CLI. `details.rateLimit.resetSeconds` is how long the window needs to drain. |
| `UNSUPPORTED_FILTER` | Remove the filter and retry. |
Expand Down
2 changes: 2 additions & 0 deletions src/__tests__/response-meta.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,12 +169,14 @@ describe('creditWarning', () => {
it('warns when the balance is exhausted', () => {
const warning = creditWarning({ credits: { used: 5, remaining: 0 } });
expect(warning).toContain('Out of API credits');
expect(warning).toContain('https://app.nansen.ai/auth/agent-setup');
});

it('warns when the balance will not cover another call of the same size', () => {
const warning = creditWarning({ credits: { used: 10, remaining: 3 } });
expect(warning).toContain('3 API credits left');
expect(warning).toContain('less than this call cost (10)');
expect(warning).toContain('https://app.nansen.ai/auth/agent-setup');
});

it('singularises one remaining credit', () => {
Expand Down
4 changes: 2 additions & 2 deletions src/response-meta.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,12 +118,12 @@ export function creditWarning(meta) {
const { used, remaining, cost } = credits;
if (remaining === null) return null;
if (remaining === 0) {
return '⚠️ Out of API credits. Top up at https://app.nansen.ai/api';
return '⚠️ Out of API credits. Top up at https://app.nansen.ai/auth/agent-setup';
Comment thread
gulshngill marked this conversation as resolved.
Outdated
}
// The cost header is the authoritative charge; used is the fallback.
const charged = cost ?? used;
if (charged !== null && charged > 0 && remaining < charged) {
return `⚠️ ${remaining} API credit${remaining === 1 ? '' : 's'} left — less than this call cost (${charged}). Top up at https://app.nansen.ai/api`;
return `⚠️ ${remaining} API credit${remaining === 1 ? '' : 's'} left — less than this call cost (${charged}). Top up at https://app.nansen.ai/auth/agent-setup`;
}
return null;
}
Loading