bind-alias-mcp
Advanced tools
+66
-42
@@ -43,2 +43,14 @@ #!/usr/bin/env node | ||
| // Shared optional params for every tool that returns the standard envelope. | ||
| const VERBOSE_PARAM = { | ||
| type: "boolean", | ||
| description: | ||
| "Optional (default false). When true, the envelope's state is the FULL snapshot instead of the diff.", | ||
| }; | ||
| const NAP_PARAM = { | ||
| type: "integer", | ||
| description: | ||
| "Optional (1-1200). Defer the tool call's response by N client_tick: the action runs immediately, but the envelope is captured only after N client_tick have elapsed. The game keeps running the whole time — you cannot react to anything or poll state until the call returns. N >= 10 fast-forwards a singleplayer world (~20 tps) for the nap.", | ||
| }; | ||
| const TOOLS = [ | ||
@@ -54,9 +66,6 @@ { | ||
| description: | ||
| 'Alias chain definition. Space for alias(with arg) separator, backslash for alias_name-arg separator or arg-arg separator, " quotes multi-word arg preventing space inside to be parsed as alias(with arg) separator: e.g. `say\\"hello world"`. Semicolon for alias\'s (the alias named as `alias`) extra separator: e.g. `alias\\turnDown;setPitch\\90`, `alias\\turnRight;yaw\\90`', | ||
| "Alias chain definition. Space(' ') for alias(with arg) separator, slash('/') for alias_name-arg separator or arg-arg separator, quote('\"') quotes multi-word arg preventing space inside to be parsed as alias(with arg) separator: e.g. `say/\"hello world\"`. Semicolon for alias's (the alias named as `alias`) extra separator: e.g. `alias/turnDown;setPitch/90`, `alias/turnRight;yaw/90`", | ||
| }, | ||
| nap: { | ||
| type: "integer", | ||
| description: | ||
| "Defer the tool call's response by N client_tick. The chain runs immediately; the response then blocks until N client_tick have elapsed. The game keeps running the whole time — you cannot react to anything or poll state until the call returns.", | ||
| }, | ||
| nap: NAP_PARAM, | ||
| verbose: VERBOSE_PARAM, | ||
| }, | ||
@@ -67,10 +76,9 @@ required: ["def"], | ||
| { | ||
| name: "getFullState", | ||
| description: "Get full state and drain messages.", | ||
| inputSchema: { type: "object", properties: {}, required: [] }, | ||
| }, | ||
| { | ||
| name: "getScreenshot", | ||
| description: "Screenshot, and standard envelope.", | ||
| inputSchema: { type: "object", properties: {}, required: [] }, | ||
| inputSchema: { | ||
| type: "object", | ||
| properties: { nap: NAP_PARAM, verbose: VERBOSE_PARAM }, | ||
| required: [], | ||
| }, | ||
| }, | ||
@@ -92,2 +100,4 @@ { | ||
| }, | ||
| nap: NAP_PARAM, | ||
| verbose: VERBOSE_PARAM, | ||
| }, | ||
@@ -120,2 +130,4 @@ required: ["name", "def"], | ||
| }, | ||
| nap: NAP_PARAM, | ||
| verbose: VERBOSE_PARAM, | ||
| }, | ||
@@ -167,4 +179,4 @@ required: ["content"], | ||
| "With 'queries' (result-item ids like 'minecraft:torch' or 'torch', or locale-name substrings like 'iron sword'): every query is answered independently — matches land in 'recipes', per-query failures in 'recipe_errors'. " + | ||
| "Entries: {name, item, craftable}. craftable=true means the ingredients are in your inventory right now. " + | ||
| "Returns the standard envelope plus recipes/recipe_errors (see the 'getFullState' description).", | ||
| "Entries: {name, item, craftable, placeable}. craftable=true means the ingredients are in your inventory right now; placeable=false means the open menu cannot place it (grid too small or wrong station). " + | ||
| "Returns the standard envelope plus recipes/recipe_errors.", | ||
| inputSchema: { | ||
@@ -179,2 +191,4 @@ type: "object", | ||
| }, | ||
| nap: NAP_PARAM, | ||
| verbose: VERBOSE_PARAM, | ||
| }, | ||
@@ -201,6 +215,6 @@ required: [], | ||
| function apiGet(path, params) { | ||
| function apiGet(path, params, timeoutMs) { | ||
| const url = buildUrl(path, params); | ||
| return new Promise((resolve) => { | ||
| const req = http.get(url, { timeout: 10000 }, (res) => { | ||
| const req = http.get(url, { timeout: timeoutMs || 10000 }, (res) => { | ||
| let data = ""; | ||
@@ -313,9 +327,18 @@ res.on("data", (chunk) => { | ||
| // Shared envelope plumbing: pass through the optional verbose/nap fields; | ||
| // a nap extends the HTTP timeout (a client_tick is ~50 ms at nominal speed). | ||
| function envelopeParams(args) { | ||
| const params = {}; | ||
| if (args.verbose === true) params.verbose = "1"; | ||
| const nap = Number(args.nap); | ||
| const napTicks = Number.isInteger(nap) && nap >= 1 && nap <= 1200 ? nap : 0; | ||
| if (napTicks > 0) params.nap = String(napTicks); | ||
| return { params, napTicks }; | ||
| } | ||
| async function handleToolCall(toolName, args) { | ||
| switch (toolName) { | ||
| case "getFullState": | ||
| return wrapResult(await apiGet("/state")); | ||
| case "getScreenshot": { | ||
| const result = await apiGet("/screenshot"); | ||
| const { params, napTicks } = envelopeParams(args); | ||
| const result = await apiGet("/screenshot", params, 10000 + napTicks * 50); | ||
| if (result.error) return wrapResult(result); | ||
@@ -334,7 +357,4 @@ if (result.base64) { | ||
| case "runAlias": { | ||
| const nap = Number(args.nap); | ||
| const napTicks = | ||
| Number.isInteger(nap) && nap >= 1 && nap <= 1200 ? nap : 0; | ||
| const params = { def: args.def || "" }; | ||
| if (napTicks > 0) params.nap = String(napTicks); | ||
| const { params, napTicks } = envelopeParams(args); | ||
| params.def = args.def || ""; | ||
| const result = await apiPost( | ||
@@ -350,6 +370,11 @@ "/runAlias", | ||
| case "defineAlias": { | ||
| const result = await apiPost("/defineAlias", { | ||
| name: args.name || "", | ||
| def: args.def || "", | ||
| }); | ||
| const { params, napTicks } = envelopeParams(args); | ||
| params.name = args.name || ""; | ||
| params.def = args.def || ""; | ||
| const result = await apiPost( | ||
| "/defineAlias", | ||
| params, | ||
| null, | ||
| 10000 + napTicks * 50, | ||
| ); | ||
| return wrapResult(result); | ||
@@ -361,11 +386,9 @@ } | ||
| case "writeCFG": | ||
| case "writeCFG": { | ||
| const { params, napTicks } = envelopeParams(args); | ||
| params.content = args.content || ""; | ||
| return wrapResult( | ||
| await apiPost( | ||
| "/writeCFG", | ||
| { content: args.content || "" }, | ||
| null, | ||
| 30000, | ||
| ), | ||
| await apiPost("/writeCFG", params, null, 30000 + napTicks * 50), | ||
| ); | ||
| } | ||
@@ -375,7 +398,8 @@ case "listRecipes": { | ||
| if (typeof queries === "string") queries = [queries]; | ||
| const params = | ||
| Array.isArray(queries) && queries.length > 0 | ||
| ? { q: queries.join(",") } | ||
| : null; | ||
| return wrapResult(await apiGet("/listRecipes", params)); | ||
| const { params, napTicks } = envelopeParams(args); | ||
| if (Array.isArray(queries) && queries.length > 0) | ||
| params.q = queries.join(","); | ||
| return wrapResult( | ||
| await apiGet("/listRecipes", params, 10000 + napTicks * 50), | ||
| ); | ||
| } | ||
@@ -459,3 +483,3 @@ | ||
| capabilities: { tools: {} }, | ||
| serverInfo: { name: "bind-alias-mcp", version: "2.1.0" }, | ||
| serverInfo: { name: "bind-alias-mcp", version: "3.0.0" }, | ||
| }), | ||
@@ -462,0 +486,0 @@ ); |
+1
-1
| { | ||
| "name": "bind-alias-mcp", | ||
| "version": "2.1.2", | ||
| "version": "2.2.0", | ||
| "mcpName": "io.github.Prohect/bind-alias-mcp", | ||
@@ -5,0 +5,0 @@ "description": "MCP stdio bridge for the BindAlias Minecraft mod — query game state, take screenshots, execute aliases, and edit config", |
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
19947
5.93%464
5.45%2
-33.33%