@tonnode/mcp
Advanced tools
+44
-43
@@ -1,5 +0,4 @@ | ||
| #!/usr/bin/env node | ||
| // Hosted mode: the same TON MCP server over Streamable HTTP. | ||
| // | ||
| // PORT=8808 TONNODE_KEYS=tn_live_abc,tn_live_def tonnode-mcp-http | ||
| // PORT=8808 TONNODE_KEYS=tn_live_abc,tn_live_def npx -y @tonnode/mcp --http | ||
| // | ||
@@ -77,45 +76,47 @@ // Clients connect with: | ||
| // ---------- http server ---------- | ||
| const httpServer = createHttpServer(async (req, res) => { | ||
| try { | ||
| const url = new URL(req.url ?? "/", "http://localhost"); | ||
| if (req.method === "GET" && url.pathname === "/healthz") { | ||
| return reply(res, 200, { ok: true, sessions: transports.size }); | ||
| } | ||
| if (url.pathname !== "/mcp") { | ||
| return reply(res, 404, { error: "not found — MCP endpoint is POST /mcp" }); | ||
| } | ||
| const key = authenticate(req); | ||
| if (!key) | ||
| return reply(res, 401, { error: "invalid or missing API key" }); | ||
| if (!allow(key)) | ||
| return reply(res, 429, { error: `rate limit exceeded (${RATE_LIMIT_RPM}/min)` }); | ||
| const sessionId = req.headers["mcp-session-id"]; | ||
| if (req.method === "POST") { | ||
| const body = await readBody(req); | ||
| let transport = sessionId ? transports.get(sessionId) : undefined; | ||
| if (!transport) { | ||
| if (sessionId) | ||
| return reply(res, 404, { error: "unknown or expired session" }); | ||
| transport = await newSession(); | ||
| export function startHttp() { | ||
| const httpServer = createHttpServer(async (req, res) => { | ||
| try { | ||
| const url = new URL(req.url ?? "/", "http://localhost"); | ||
| if (req.method === "GET" && url.pathname === "/healthz") { | ||
| return reply(res, 200, { ok: true, sessions: transports.size }); | ||
| } | ||
| return void (await transport.handleRequest(req, res, body)); | ||
| if (url.pathname !== "/mcp") { | ||
| return reply(res, 404, { error: "not found — MCP endpoint is POST /mcp" }); | ||
| } | ||
| const key = authenticate(req); | ||
| if (!key) | ||
| return reply(res, 401, { error: "invalid or missing API key" }); | ||
| if (!allow(key)) | ||
| return reply(res, 429, { error: `rate limit exceeded (${RATE_LIMIT_RPM}/min)` }); | ||
| const sessionId = req.headers["mcp-session-id"]; | ||
| if (req.method === "POST") { | ||
| const body = await readBody(req); | ||
| let transport = sessionId ? transports.get(sessionId) : undefined; | ||
| if (!transport) { | ||
| if (sessionId) | ||
| return reply(res, 404, { error: "unknown or expired session" }); | ||
| transport = await newSession(); | ||
| } | ||
| return void (await transport.handleRequest(req, res, body)); | ||
| } | ||
| // GET = server-initiated SSE stream, DELETE = session teardown | ||
| if (req.method === "GET" || req.method === "DELETE") { | ||
| const transport = sessionId ? transports.get(sessionId) : undefined; | ||
| if (!transport) | ||
| return reply(res, 400, { error: "mcp-session-id header required" }); | ||
| return void (await transport.handleRequest(req, res)); | ||
| } | ||
| return reply(res, 405, { error: "method not allowed" }); | ||
| } | ||
| // GET = server-initiated SSE stream, DELETE = session teardown | ||
| if (req.method === "GET" || req.method === "DELETE") { | ||
| const transport = sessionId ? transports.get(sessionId) : undefined; | ||
| if (!transport) | ||
| return reply(res, 400, { error: "mcp-session-id header required" }); | ||
| return void (await transport.handleRequest(req, res)); | ||
| catch (err) { | ||
| const message = err instanceof Error ? err.message : String(err); | ||
| if (!res.headersSent) | ||
| reply(res, 500, { error: message }); | ||
| } | ||
| return reply(res, 405, { error: "method not allowed" }); | ||
| } | ||
| catch (err) { | ||
| const message = err instanceof Error ? err.message : String(err); | ||
| if (!res.headersSent) | ||
| reply(res, 500, { error: message }); | ||
| } | ||
| }); | ||
| httpServer.listen(PORT, () => { | ||
| const mode = KEYS.size > 0 ? `${KEYS.size} API key(s)` : "open access (no TONNODE_KEYS set)"; | ||
| console.error(`tonnode-mcp http listening on :${PORT} — ${mode}, ${RATE_LIMIT_RPM} req/min per key`); | ||
| }); | ||
| }); | ||
| httpServer.listen(PORT, () => { | ||
| const mode = KEYS.size > 0 ? `${KEYS.size} API key(s)` : "open access (no TONNODE_KEYS set)"; | ||
| console.error(`tonnode-mcp http listening on :${PORT} — ${mode}, ${RATE_LIMIT_RPM} req/min per key`); | ||
| }); | ||
| } |
+16
-7
| #!/usr/bin/env node | ||
| import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; | ||
| import { createTonServer } from "./server.js"; | ||
| await createTonServer().connect(new StdioServerTransport()); | ||
| // open liteserver sockets keep the event loop alive — exit when the MCP | ||
| // client (or a closed pipe) ends stdin, so orphaned servers don't linger | ||
| process.stdin.on("end", () => process.exit(0)); | ||
| process.stdin.on("close", () => process.exit(0)); | ||
| // Default: stdio MCP server for local clients (Claude, ChatGPT, Cursor, Codex…). | ||
| // With --http: hosted Streamable-HTTP mode (API keys, rate limits) — see src/http.ts. | ||
| if (process.argv.includes("--http")) { | ||
| const { startHttp } = await import("./http.js"); | ||
| startHttp(); | ||
| } | ||
| else { | ||
| const { StdioServerTransport } = await import("@modelcontextprotocol/sdk/server/stdio.js"); | ||
| const { createTonServer } = await import("./server.js"); | ||
| await createTonServer().connect(new StdioServerTransport()); | ||
| // open liteserver sockets keep the event loop alive — exit when the MCP | ||
| // client (or a closed pipe) ends stdin, so orphaned servers don't linger | ||
| process.stdin.on("end", () => process.exit(0)); | ||
| process.stdin.on("close", () => process.exit(0)); | ||
| } | ||
| export {}; |
+2
-3
| { | ||
| "name": "@tonnode/mcp", | ||
| "version": "0.1.0", | ||
| "version": "0.1.1", | ||
| "description": "MCP server that gives AI agents direct liteserver access to The Open Network (TON): balances, account state, transactions and contract get-methods.", | ||
| "type": "module", | ||
| "bin": { | ||
| "tonnode-mcp": "dist/index.js", | ||
| "tonnode-mcp-http": "dist/http.js" | ||
| "tonnode-mcp": "dist/index.js" | ||
| }, | ||
@@ -10,0 +9,0 @@ "main": "dist/index.js", |
+1
-1
@@ -39,3 +39,3 @@ # @tonnode/mcp | ||
| ```bash | ||
| TONNODE_KEYS=tn_live_abc,tn_live_def PORT=8808 npx -y -p @tonnode/mcp tonnode-mcp-http | ||
| TONNODE_KEYS=tn_live_abc,tn_live_def PORT=8808 npx -y @tonnode/mcp --http | ||
| ``` | ||
@@ -42,0 +42,0 @@ |
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Deprecated
MaintenanceThe maintainer of the package marked it as deprecated. This could indicate that a single version should not be used, or that the package is no longer maintained and any new vulnerabilities will not be fixed.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
22046
2.31%380
2.7%0
-100%