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. |
||
|---|---|---|
| .github | ||
| src | ||
| .gitignore | ||
| LICENSE | ||
| package.json | ||
| pnpm-lock.yaml | ||
| pnpm-workspace.yaml | ||
| README.md | ||
| tsconfig.json | ||
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.
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_tokensandvectr_search_tokendescribe the row as having achange24hfield and apair. Whether those are populated depends on the backend'sTokenRow, which this repo mirrors by hand in a 4-line interface with every field optional. If the backend renames something, the tool returnsundefinedquietly 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.mcpblock the backend serves on/configlists 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.