MCP server at POST /mcp (official SDK, stateless Streamable HTTP) (#11)
CI / build + unit (push) Successful in 1m6s

This commit was merged in pull request #11.
This commit is contained in:
2026-09-24 20:39:45 +02:00
parent 108aa400d3
commit b31fb35464
11 changed files with 719 additions and 75 deletions
+8 -64
View File
@@ -1,62 +1,20 @@
import { create, fromBinary, toBinary } from '@bufbuild/protobuf';
import * as P from '@meshtastic/protobufs';
import * as net from 'node:net';
import type { AddressInfo } from 'node:net';
import { describe, expect, it } from 'vitest';
import { BROADCAST_ADDR, extractFrames, frame } from './codec.js';
import {
KAMIL_NUM,
kamilNodeInfo,
nodeInfoFrame,
startBridge,
waitFor,
} from './fake-bridge.js';
import { MeshService } from './mesh.service.js';
function startBridge(onSocket?: (s: net.Socket) => void): Promise<{
port: number;
sockets: net.Socket[];
close: () => void;
}> {
const sockets: net.Socket[] = [];
const server = net.createServer((socket) => {
onSocket?.(socket); // attached at accept time, before any data can arrive
sockets.push(socket);
});
return new Promise((resolve) => {
server.listen(0, '127.0.0.1', () => {
resolve({
port: (server.address() as AddressInfo).port,
sockets,
close: () => server.close(),
});
});
});
}
async function waitFor(
cond: () => boolean | Promise<boolean>,
timeoutMs = 5000,
): Promise<void> {
const t0 = Date.now();
while (!(await cond())) {
if (Date.now() - t0 > timeoutMs) throw new Error('timed out waiting');
await new Promise((r) => setTimeout(r, 10));
}
}
function nodeInfoFrame(
num: number,
fields?: Partial<P.Mesh.NodeInfo>,
): Uint8Array {
const ni = create(P.Mesh.NodeInfoSchema, { num, ...fields });
return frame(
toBinary(
P.Mesh.FromRadioSchema,
create(P.Mesh.FromRadioSchema, {
payloadVariant: { case: 'nodeInfo', value: ni },
}),
),
);
}
// live position update: POSITION_APP packet with a serialized Position in Data.payload
function positionPacketFrame(
from: number,
pos: Partial<P.Mesh.Position>,
pos: { latitudeI?: number; longitudeI?: number },
): Uint8Array {
const data = create(P.Mesh.DataSchema, {
portnum: P.Portnums.PortNum.POSITION_APP,
@@ -80,7 +38,6 @@ function positionPacketFrame(
);
}
const KAMIL_NUM = 123456789;
// inbound text message: TEXT_MESSAGE_APP packet with UTF-8 in Data.payload
function textPacketFrame(
from: number,
@@ -138,19 +95,6 @@ function routingFrame(
),
);
}
function kamilNodeInfo(): Partial<P.Mesh.NodeInfo> {
return {
user: {
id: '!kamil',
longName: 'Kamil SP8MK/P',
shortName: 'KK',
hwModel: P.Mesh.HardwareModel.TBEAM,
},
position: { latitudeI: 521049637, longitudeI: 209833152, altitude: 123 },
lastHeard: 1758000000,
deviceMetrics: { batteryLevel: 87 },
};
}
function channelFrame(
index: number,