Skip to content

Commit 325b42e

Browse files
hyperpolymathclaude
andcommitted
feat(cartridges): V-lang sweep batch 3 — cloud, databases, comms (19 cartridges)
cartridges converted (19): Cloud: aws-mcp, gcp-mcp, k8s-mcp, container-mcp, iac-mcp DB: database-mcp, postgresql-mcp, mongodb-mcp, redis-mcp, clickhouse-mcp, duckdb-mcp, neon-mcp, supabase-mcp, turso-mcp, arango-mcp Comms: slack-mcp, discord-mcp, telegram-mcp, matrix-mcp Per cartridge (full treatment): - cartridge.json with tool schemas - mod.js Deno handler (HTTP delegation to local backend) - adapter/<name>_adapter.zig: REST/gRPC/GraphQL ports 9139-9195 - adapter/build.zig where missing - adapter/SIDELINED-*.adoc - git rm .v file .v count: 70 → 51. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent cb00882 commit 325b42e

114 files changed

Lines changed: 7580 additions & 4282 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
= SIDELINED: arango_mcp_adapter.v
2+
3+
V-lang banned 2026-04-12. Replaced by `arango_mcp_adapter.zig`.
4+
5+
Ports: REST 9181 / gRPC 9182 / GraphQL 9183. FFI unchanged: `arango_mcp_ffi.zig`.

cartridges/arango-mcp/adapter/arango_mcp_adapter.v

Lines changed: 0 additions & 162 deletions
This file was deleted.
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// SPDX-License-Identifier: PMPL-1.0-or-later
2+
// Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
3+
//
4+
// arango-mcp/adapter/arango_mcp_adapter.zig -- Unified three-protocol adapter.
5+
// Replaces banned arango_mcp_adapter.v (V-lang, removed 2026-04-12).
6+
// REST:9181 gRPC:9182 GraphQL:9183
7+
// Tools: arango_connect, arango_aql, arango_insert, arango_get...
8+
9+
const std = @import("std");
10+
const ffi = @import("arango_mcp_ffi");
11+
12+
const REST_PORT: u16 = 9181;
13+
const GRPC_PORT: u16 = 9182;
14+
const GQL_PORT: u16 = 9183;
15+
const MAX_CONN_BUF: usize = 16 * 1024;
16+
17+
fn okJson(buf: []u8, msg: []const u8) []u8 {
18+
const n = std.fmt.bufPrint(buf, "{\"success\":true,\"message\":\"{s}\"}", .{msg}) catch return buf[0..0]; return n;
19+
}
20+
fn errJson(buf: []u8, msg: []const u8) []u8 {
21+
const n = std.fmt.bufPrint(buf, "{\"success\":false,\"error\":\"{s}\"}", .{msg}) catch return buf[0..0]; return n;
22+
}
23+
fn statusJson(buf: []u8) []u8 {
24+
const n = std.fmt.bufPrint(buf, "{\"success\":true,\"state\":\"ready\",\"service\":\"arango-mcp\"}", .{}) catch return buf[0..0]; return n;
25+
}
26+
27+
const Response = struct { status: u16, body: []u8 };
28+
29+
fn dispatch(tool: []const u8, body: []const u8, resp: []u8) Response {
30+
_ = body;
31+
if (std.mem.eql(u8, tool, "arango_connect")) return .{ .status = 200, .body = okJson(resp, "arango_connect forwarded") };
32+
if (std.mem.eql(u8, tool, "arango_aql")) return .{ .status = 200, .body = okJson(resp, "arango_aql forwarded") };
33+
if (std.mem.eql(u8, tool, "arango_insert")) return .{ .status = 200, .body = okJson(resp, "arango_insert forwarded") };
34+
if (std.mem.eql(u8, tool, "arango_get")) return .{ .status = 200, .body = okJson(resp, "arango_get forwarded") };
35+
if (std.mem.eql(u8, tool, "arango_update")) return .{ .status = 200, .body = okJson(resp, "arango_update forwarded") };
36+
if (std.mem.eql(u8, tool, "arango_delete")) return .{ .status = 200, .body = okJson(resp, "arango_delete forwarded") };
37+
if (std.mem.eql(u8, tool, "arango_graph_traversal")) return .{ .status = 200, .body = okJson(resp, "arango_graph_traversal forwarded") };
38+
if (std.mem.eql(u8, tool, "arango_list_collections")) return .{ .status = 200, .body = okJson(resp, "arango_list_collections forwarded") };
39+
if (std.mem.eql(u8, tool, "arango_disconnect")) return .{ .status = 200, .body = okJson(resp, "arango_disconnect forwarded") };
40+
if (std.mem.eql(u8, tool, "status") or std.mem.eql(u8, tool, "health")) return .{ .status = 200, .body = statusJson(resp) };
41+
return .{ .status = 404, .body = errJson(resp, "Unknown tool") };
42+
}
43+
44+
fn dispatchRest(path: []const u8, body: []const u8, resp: []u8) Response {
45+
if (std.mem.startsWith(u8, path, "/tools/")) return dispatch(path["/tools/".len..], body, resp);
46+
if (std.mem.eql(u8, path, "/status") or std.mem.eql(u8, path, "/health")) return .{ .status = 200, .body = statusJson(resp) };
47+
return .{ .status = 404, .body = errJson(resp, "Not found") };
48+
}
49+
50+
fn dispatchGrpc(path: []const u8, body: []const u8, resp: []u8) Response {
51+
const prefix = "/ArangoMcpservice/";
52+
if (!std.mem.startsWith(u8, path, prefix)) return .{ .status = 404, .body = errJson(resp, "Not a recognized gRPC path") };
53+
const method = path[prefix.len..];
54+
const tool = blk: {
55+
if (std.mem.eql(u8, method, "arango_connect")) break :blk "arango_connect";
56+
if (std.mem.eql(u8, method, "arango_aql")) break :blk "arango_aql";
57+
if (std.mem.eql(u8, method, "arango_insert")) break :blk "arango_insert";
58+
if (std.mem.eql(u8, method, "arango_get")) break :blk "arango_get";
59+
if (std.mem.eql(u8, method, "arango_update")) break :blk "arango_update";
60+
if (std.mem.eql(u8, method, "arango_delete")) break :blk "arango_delete";
61+
if (std.mem.eql(u8, method, "arango_graph_traversal")) break :blk "arango_graph_traversal";
62+
if (std.mem.eql(u8, method, "arango_list_collections")) break :blk "arango_list_collections";
63+
if (std.mem.eql(u8, method, "arango_disconnect")) break :blk "arango_disconnect";
64+
return .{ .status = 404, .body = errJson(resp, "Unknown gRPC method") };
65+
};
66+
return dispatch(tool, body, resp);
67+
}
68+
69+
fn dispatchGraphql(body: []const u8, resp: []u8) Response {
70+
if (std.mem.indexOf(u8, body, "__schema") != null) return .{ .status = 200, .body = okJson(resp, "schema not supported") };
71+
if (std.mem.indexOf(u8, body, "connect") != null) return dispatch("arango_connect", body, resp);
72+
if (std.mem.indexOf(u8, body, "aql") != null) return dispatch("arango_aql", body, resp);
73+
if (std.mem.indexOf(u8, body, "insert") != null) return dispatch("arango_insert", body, resp);
74+
if (std.mem.indexOf(u8, body, "get") != null) return dispatch("arango_get", body, resp);
75+
if (std.mem.indexOf(u8, body, "update") != null) return dispatch("arango_update", body, resp);
76+
if (std.mem.indexOf(u8, body, "delete") != null) return dispatch("arango_delete", body, resp);
77+
if (std.mem.indexOf(u8, body, "graph_traversal") != null) return dispatch("arango_graph_traversal", body, resp);
78+
if (std.mem.indexOf(u8, body, "list_collections") != null) return dispatch("arango_list_collections", body, resp);
79+
if (std.mem.indexOf(u8, body, "disconnect") != null) return dispatch("arango_disconnect", body, resp);
80+
return .{ .status = 200, .body = errJson(resp, "Unrecognised GraphQL operation") };
81+
}
82+
83+
const Protocol = enum { rest, grpc, graphql };
84+
85+
fn handleConnection(conn: std.net.Server.Connection, proto: Protocol) void {
86+
defer conn.stream.close();
87+
var in_buf: [MAX_CONN_BUF]u8 = undefined;
88+
const n = conn.stream.read(&in_buf) catch return;
89+
const req = in_buf[0..n];
90+
var path: []const u8 = "/"; var body: []const u8 = "";
91+
if (n > 4) {
92+
const le = std.mem.indexOf(u8, req, "\r\n") orelse req.len;
93+
const fl = req[0..le]; const sp1 = std.mem.indexOfScalar(u8, fl, ' ') orelse 0;
94+
const ro = fl[sp1+1..]; const sp2 = std.mem.indexOfScalar(u8, ro, ' ') orelse ro.len;
95+
path = ro[0..sp2];
96+
const bs = std.mem.indexOf(u8, req, "\r\n\r\n") orelse n; body = req[@min(bs+4,n)..];
97+
}
98+
var rb: [MAX_CONN_BUF]u8 = undefined;
99+
const result = switch (proto) { .rest => dispatchRest(path, body, &rb), .grpc => dispatchGrpc(path, body, &rb), .graphql => dispatchGraphql(body, &rb) };
100+
const ct: []const u8 = if (proto == .grpc) "application/grpc+json" else "application/json";
101+
var hb: [256]u8 = undefined;
102+
const hdr = std.fmt.bufPrint(&hb, "HTTP/1.1 {d} OK\r\nContent-Type: {s}\r\nContent-Length: {d}\r\nConnection: close\r\n\r\n", .{ result.status, ct, result.body.len }) catch return;
103+
_ = conn.stream.writeAll(hdr) catch return; _ = conn.stream.writeAll(result.body) catch return;
104+
}
105+
106+
fn listenLoop(port: u16, proto: Protocol) void {
107+
const addr = std.net.Address.initIp4(.{ 127, 0, 0, 1 }, port) catch return;
108+
var srv = addr.listen(.{ .reuse_address = true }) catch return; defer srv.deinit();
109+
while (true) { const conn = srv.accept() catch continue; handleConnection(conn, proto); }
110+
}
111+
112+
pub fn main() !void {
113+
ffi.arango_mcp_init();
114+
const t1 = try std.Thread.spawn(.{}, listenLoop, .{ REST_PORT, Protocol.rest });
115+
const t2 = try std.Thread.spawn(.{}, listenLoop, .{ GRPC_PORT, Protocol.grpc });
116+
const t3 = try std.Thread.spawn(.{}, listenLoop, .{ GQL_PORT, Protocol.graphql });
117+
t1.join(); t2.join(); t3.join();
118+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// SPDX-License-Identifier: PMPL-1.0-or-later
2+
// Copyright (c) 2026 Jonathan D.A. Jewell (hyperpolymath) <j.d.a.jewell@open.ac.uk>
3+
//
4+
// arango-mcp/adapter/build.zig
5+
6+
const std = @import("std");
7+
8+
pub fn build(b: *std.Build) void {
9+
const target = b.standardTargetOptions(.{}); const optimize = b.standardOptimizeOption(.{});
10+
const ffi_mod = b.createModule(.{ .root_source_file = b.path("../ffi/arango_mcp_ffi.zig"), .target = target, .optimize = optimize });
11+
const adapter = b.addExecutable(.{ .name = "arango_mcp_adapter", .root_source_file = b.path("arango_mcp_adapter.zig"), .target = target, .optimize = optimize });
12+
adapter.root_module.addImport("arango_mcp_ffi", ffi_mod); b.installArtifact(adapter);
13+
const rs = b.step("run", "Run arango-mcp adapter"); rs.dependOn(&b.addRunArtifact(adapter).step);
14+
const tests = b.addTest(.{ .root_source_file = b.path("arango_mcp_adapter.zig"), .target = target, .optimize = optimize });
15+
tests.root_module.addImport("arango_mcp_ffi", ffi_mod);
16+
const ts = b.step("test", "Test arango-mcp adapter"); ts.dependOn(&b.addRunArtifact(tests).step);
17+
}

0 commit comments

Comments
 (0)