Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@codespar/mcp-bitso

Package Overview
Dependencies
Maintainers
1
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@codespar/mcp-bitso - npm Package Compare versions

Comparing version
0.1.0
to
0.1.2
+30
server.json
{
"$schema": "https://static.modelcontextprotocol.io/schemas/2025-12-11/server.schema.json",
"name": "io.github.codespar/mcp-bitso",
"description": "MCP server for Bitso — Latin American crypto exchange, trading, funding, withdrawals",
"repository": {
"url": "https://github.com/codespar/mcp-dev-brasil",
"source": "github",
"subfolder": "packages/crypto/bitso"
},
"version": "0.1.2",
"packages": [
{
"registryType": "npm",
"identifier": "@codespar/mcp-bitso",
"version": "0.1.2",
"transport": {
"type": "stdio"
},
"environmentVariables": [
{
"name": "BITSO_API_KEY",
"description": "API key for bitso",
"isRequired": true,
"format": "string",
"isSecret": true
}
]
}
]
}
import { describe, it, expect, vi, beforeEach } from "vitest";
let listToolsHandler: Function;
let callToolHandler: Function;
vi.mock("@modelcontextprotocol/sdk/server/index.js", () => {
class FakeServer {
constructor() {}
setRequestHandler(schema: any, handler: Function) {
if (JSON.stringify(schema).includes("tools/list")) listToolsHandler = handler;
if (JSON.stringify(schema).includes("tools/call")) callToolHandler = handler;
}
connect() { return Promise.resolve(); }
}
return { Server: FakeServer };
});
vi.mock("@modelcontextprotocol/sdk/server/stdio.js", () => ({ StdioServerTransport: class {} }));
process.env.BITSO_API_KEY = "test-key";
process.env.BITSO_API_SECRET = "test-secret";
const mockFetch = vi.fn();
global.fetch = mockFetch as any;
beforeEach(async () => {
vi.resetModules();
listToolsHandler = undefined as any;
callToolHandler = undefined as any;
mockFetch.mockReset();
global.fetch = mockFetch as any;
await import("../index.js");
});
describe("mcp-bitso", () => {
it("should register 10 tools", async () => {
const result = await listToolsHandler();
expect(result.tools).toHaveLength(10);
});
it("should call correct API endpoint for get_ticker", async () => {
mockFetch.mockResolvedValueOnce({ ok: true, json: () => Promise.resolve({ success: true, payload: { last: "100000" } }) });
await callToolHandler({ params: { name: "get_ticker", arguments: { book: "btc_brl" } } });
const [url] = mockFetch.mock.calls[0];
expect(url).toContain("api.bitso.com/v3/ticker");
expect(url).toContain("book=btc_brl");
});
});
+41
-8

@@ -23,2 +23,4 @@ #!/usr/bin/env node

import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";

@@ -229,13 +231,44 @@ import * as crypto from "node:crypto";

async function main() {
if (!API_KEY) {
console.error("BITSO_API_KEY environment variable is required");
process.exit(1);
if (process.argv.includes("--http") || process.env.MCP_HTTP === "true") {
const { default: express } = await import("express");
const { randomUUID } = await import("node:crypto");
const app = express();
app.use(express.json());
const transports = new Map();
app.get("/health", (_req, res) => res.json({ status: "ok", sessions: transports.size }));
app.post("/mcp", async (req, res) => {
const sid = req.headers["mcp-session-id"];
if (sid && transports.has(sid)) {
await transports.get(sid).handleRequest(req, res, req.body);
return;
}
if (!sid && isInitializeRequest(req.body)) {
const t = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID(), onsessioninitialized: (id) => { transports.set(id, t); } });
t.onclose = () => { if (t.sessionId)
transports.delete(t.sessionId); };
const s = new Server({ name: "mcp-bitso", version: "0.1.0" }, { capabilities: { tools: {} } });
server._requestHandlers.forEach((v, k) => s._requestHandlers.set(k, v));
server._notificationHandlers?.forEach((v, k) => s._notificationHandlers.set(k, v));
await s.connect(t);
await t.handleRequest(req, res, req.body);
return;
}
res.status(400).json({ jsonrpc: "2.0", error: { code: -32000, message: "Bad Request" }, id: null });
});
app.get("/mcp", async (req, res) => { const sid = req.headers["mcp-session-id"]; if (sid && transports.has(sid))
await transports.get(sid).handleRequest(req, res);
else
res.status(400).send("Invalid session"); });
app.delete("/mcp", async (req, res) => { const sid = req.headers["mcp-session-id"]; if (sid && transports.has(sid))
await transports.get(sid).handleRequest(req, res);
else
res.status(400).send("Invalid session"); });
const port = Number(process.env.MCP_PORT) || 3000;
app.listen(port, () => { console.error(`MCP HTTP server on http://localhost:${port}/mcp`); });
}
if (!API_SECRET) {
console.error("BITSO_API_SECRET environment variable is required");
process.exit(1);
else {
const transport = new StdioServerTransport();
await server.connect(transport);
}
const transport = new StdioServerTransport();
await server.connect(transport);
}
main().catch(console.error);
+3
-2
{
"name": "@codespar/mcp-bitso",
"version": "0.1.0",
"version": "0.1.2",
"description": "MCP server for Bitso — Latin American crypto exchange, trading, funding, withdrawals",

@@ -29,3 +29,4 @@ "type": "module",

"latam"
]
],
"mcpName": "io.github.codespar/mcp-bitso"
}

@@ -113,4 +113,8 @@ # @codespar/mcp-bitso

## Enterprise
Need governance, budget limits, and audit trails for agent payments? [CodeSpar Enterprise](https://codespar.dev/enterprise) adds policy engine, payment routing, and compliance templates on top of these MCP servers.
## License
MIT

@@ -25,2 +25,4 @@ #!/usr/bin/env node

import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
import {

@@ -235,14 +237,30 @@ CallToolRequestSchema,

async function main() {
if (!API_KEY) {
console.error("BITSO_API_KEY environment variable is required");
process.exit(1);
if (process.argv.includes("--http") || process.env.MCP_HTTP === "true") {
const { default: express } = await import("express");
const { randomUUID } = await import("node:crypto");
const app = express();
app.use(express.json());
const transports = new Map<string, StreamableHTTPServerTransport>();
app.get("/health", (_req: any, res: any) => res.json({ status: "ok", sessions: transports.size }));
app.post("/mcp", async (req: any, res: any) => {
const sid = req.headers["mcp-session-id"] as string | undefined;
if (sid && transports.has(sid)) { await transports.get(sid)!.handleRequest(req, res, req.body); return; }
if (!sid && isInitializeRequest(req.body)) {
const t = new StreamableHTTPServerTransport({ sessionIdGenerator: () => randomUUID(), onsessioninitialized: (id) => { transports.set(id, t); } });
t.onclose = () => { if (t.sessionId) transports.delete(t.sessionId); };
const s = new Server({ name: "mcp-bitso", version: "0.1.0" }, { capabilities: { tools: {} } }); (server as any)._requestHandlers.forEach((v: any, k: any) => (s as any)._requestHandlers.set(k, v)); (server as any)._notificationHandlers?.forEach((v: any, k: any) => (s as any)._notificationHandlers.set(k, v)); await s.connect(t);
await t.handleRequest(req, res, req.body); return;
}
res.status(400).json({ jsonrpc: "2.0", error: { code: -32000, message: "Bad Request" }, id: null });
});
app.get("/mcp", async (req: any, res: any) => { const sid = req.headers["mcp-session-id"] as string; if (sid && transports.has(sid)) await transports.get(sid)!.handleRequest(req, res); else res.status(400).send("Invalid session"); });
app.delete("/mcp", async (req: any, res: any) => { const sid = req.headers["mcp-session-id"] as string; if (sid && transports.has(sid)) await transports.get(sid)!.handleRequest(req, res); else res.status(400).send("Invalid session"); });
const port = Number(process.env.MCP_PORT) || 3000;
app.listen(port, () => { console.error(`MCP HTTP server on http://localhost:${port}/mcp`); });
} else {
const transport = new StdioServerTransport();
await server.connect(transport);
}
if (!API_SECRET) {
console.error("BITSO_API_SECRET environment variable is required");
process.exit(1);
}
const transport = new StdioServerTransport();
await server.connect(transport);
}
main().catch(console.error);