Vectr MCP server: prices, tokens and the AI agent for Claude, Cursor and any MCP client
Find a file
Vectr 97097554ac fix(agent): say that an unsigned transaction is the owner's to submit, not the Terminal's to confirm
The vectr_agent tool description and the file header both told the model that a
transaction "comes back unsigned for a human to confirm in the Vectr Terminal".
That is one true fact and one false implication. True: this server never signs.
False: that the Terminal is where the transaction has to go. The transaction is
unsigned and it belongs to the wallet owner, who can submit it from anywhere.

An MCP client reads that description to decide what to tell its user, so the
wording was steering people into a product surface rather than telling them what
they were holding. Now: "Transactions come back unsigned for the wallet owner to
review and submit; this tool never signs or broadcasts." The header matches.

No behaviour change — the server could never sign and still cannot.

packaging
---------
- `bin` entry "./dist/index.js" -> "dist/index.js". npm resolves both, but the
  leading ./ is non-canonical and some registry tooling reads it literally.
- Added `bugs.url` pointing at the Forgejo issue tracker, and twelve keywords
  (mcp, model-context-protocol, mcp-server, robinhood-chain, stock-tokens,
  crypto, trading, ai-agent, claude, cursor, token-launchpad, vectr) so the
  package is findable by what it does rather than only by name.

deps
----
@modelcontextprotocol/sdk 1.30 -> 1.32.1, zod 4.6.5 -> 4.6.7,
@types/node 25.9.1 -> 26.6.5, tsx 4.20 -> 4.23.15, with the matching
minimumReleaseAgeExclude entries.
2026-10-22 20:57:23 +03:00
.github docs: absolute banner URL, and fall back to the production API on an empty env var 2026-09-27 00:18:09 +03:00
src fix(agent): say that an unsigned transaction is the owner's to submit, not the Terminal's to confirm 2026-10-22 20:57:23 +03:00
.gitignore init: Vectr MCP server 2026-09-22 00:40:14 +03:00
LICENSE init: Vectr MCP server 2026-09-22 00:40:14 +03:00
package.json fix(agent): say that an unsigned transaction is the owner's to submit, not the Terminal's to confirm 2026-10-22 20:57:23 +03:00
pnpm-lock.yaml fix(agent): say that an unsigned transaction is the owner's to submit, not the Terminal's to confirm 2026-10-22 20:57:23 +03:00
pnpm-workspace.yaml fix(agent): say that an unsigned transaction is the owner's to submit, not the Terminal's to confirm 2026-10-22 20:57:23 +03:00
README.md docs: absolute banner URL, and fall back to the production API on an empty env var 2026-09-27 00:18:09 +03:00
tsconfig.json init: Vectr MCP server 2026-09-22 00:40:14 +03:00

Vectr: build, launch, trade

vectr-mcp

Five tools, 230 lines, stdio. Gives Claude Desktop, Claude Code, Cursor or anything else that speaks MCP a way to read Vectr's market and run its agent. It can build you a buy. It cannot send one. That's the whole design.

MCP SDK TypeScript zod Node Transport Tools Signs Lines License


What this is

One process. The MCP client spawns node dist/index.js, talks JSON-RPC over stdin and stdout, and the server turns tool calls into HTTPS requests against api.vectr.bot. No daemon, no port, no state. The single stderr line on boot (vectr-mcp ready: https://api.vectr.bot (key set)) is the entire observability story.

Two files. api.ts resolves the backend URL and key and wraps fetch. index.ts registers five tools with zod schemas and connects the stdio transport. That is all of it; there is no third file to worry about.


Install

git clone https://git.vectr.bot/vectr/mcp.git vectr-mcp
cd vectr-mcp
pnpm install
pnpm build          # tsc -> dist/index.js

Node 18 or newer. Note the absolute path of dist/index.js; every client config below wants it. Update with git pull && pnpm install && pnpm build.


Wire up a client

Claude Desktop, claude_desktop_config.json (Settings, Developer, Edit Config):

{
  "mcpServers": {
    "vectr": {
      "command": "node",
      "args": ["/absolute/path/to/vectr-mcp/dist/index.js"],
      "env": { "VECTR_API_URL": "https://api.vectr.bot", "VECTR_API_KEY": "vectr_..." }
    }
  }
}

Claude Code:

claude mcp add vectr -e VECTR_API_KEY=vectr_... -- node /absolute/path/to/vectr-mcp/dist/index.js

Cursor: .cursor/mcp.json in the project or the global MCP settings, same command, args, env.

Restart the client. The boot line lands in the client's MCP log.


Environment

Variable Default Purpose
VECTR_API_URL https://api.vectr.bot Backend base URL. Point at a dev backend to test
VECTR_API_KEY none A vectr_ key. Only vectr_agent needs it; the four reads work without

Resolution order is environment, then ~/.vectr/config.json (the file the Vectr CLI writes on vectr login), then the default. One login serves both tools. Note that this is the opposite order from the CLI, which reads the file first; see skeletons.

Keys are made at vectr.bot/profile?tab=api-keys. Read-only is enough for research. Read-write lets the agent build transactions from your Vectr wallet under that wallet's limits and allowlists, and still cannot broadcast them from here.


Tools

Tool Key Arguments Returns
vectr_get_price no none ETH $2776.80 (2776.8 USD), symbol from the backend
vectr_get_tokens no limit? 1-200, default 10 Top tokens by market cap, slimmed to 13 fields each, with a page link
vectr_search_token no query Same shape, by name, symbol or address
vectr_get_token no address (regex-checked) Full token detail plus a computed curveProgressPct against its graduation threshold
vectr_agent yes prompt, model? Submits POST /agent/job, polls every 1.5 s for up to 180 s, returns the answer and, when one was built, the transaction under a heading that says it is unsigned

When the agent builds a transaction the tool returns it as JSON with a note that the user confirms it at vectr.bot/terminal. The server has no signing endpoint to call and no key that could sign. The three-layer calldata allowlist that guards the custodial wallet lives in the backend and is not this repo's problem.

If the job outlasts 180 s the tool returns an error with the job id and tells you to poll GET /agent/job/:id yourself. The job keeps running on the backend and is billed either way.


Try it without a client

printf '%s\n' \
  '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"test","version":"0"}}}' \
  '{"jsonrpc":"2.0","method":"notifications/initialized"}' \
  '{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"vectr_get_price","arguments":{}}}' \
  | node dist/index.js

Three lines in, three JSON-RPC frames out on stdout, one status line on stderr. If stdout has anything that is not JSON-RPC, a client will choke on it; that is why the only console.error in the codebase is on stderr and there is no console.log.


Development

pnpm dev            # tsx src/index.ts, works on TypeScript 7 because tsx is esbuild, not the compiler API
pnpm build          # tsc -> dist/

ES modules, NodeNext, ES2022. Imports inside src/ end in .js because that is what NodeNext resolution wants and what tsc emits.


Layout

src/
  index.ts        McpServer, five registerTool calls, stdio transport, one stderr line
  api.ts          env > ~/.vectr/config.json > default; get/post with X-API-Key and a User-Agent
dist/             tsc output, gitignored, what `bin` points at

Skeletons in the closet

  • The CLI resolves config file first, then environment. This server resolves environment first, then the config file. Same file, same two variables, opposite precedence. Whichever one you think is right, one of the two repos disagrees with you.
  • vectr_get_tokens and vectr_search_token describe the row as having a change24h field and a pair. Whether those are populated depends on the backend's TokenRow, which this repo mirrors by hand in a 4-line interface with every field optional. If the backend renames something, the tool returns undefined quietly and the model shrugs.
  • One commit. init: Vectr MCP server. The git history is a single frame, which is either discipline or a squash.
  • The platform.mcp block the backend serves on /config lists these five tools with their descriptions, so the docs site can render them. It is a second copy of the tool list, maintained by hand, in a different repo. They match today.

License

MIT.