From d2ae725a6d5863a691a2f55d076cd5d15d6af823 Mon Sep 17 00:00:00 2001 From: Andrei Hasna Date: Tue, 7 Jul 2026 12:39:22 +0300 Subject: [PATCH] fix(mcp): route to cloud /v1 HTTP client in self_hosted mode The identities MCP server previously only knew the local file store and the in-VPC Postgres DSN path (HASNA_IDENTITIES_STORAGE_MODE=cloud). On a client machine with the self_hosted env vars set it silently ignored them and read local. Prefer the locked API-client path: when HASNA_IDENTITIES_API_URL and HASNA_IDENTITIES_API_KEY are set, route ALL reads/writes to /v1 with the bearer key (no DSN on clients). Unsetting restores the local store. Bump 0.2.1 -> 0.2.2. --- package.json | 2 +- src/mcp/index.ts | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 986ab25..1fda5d8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@hasna/identities", - "version": "0.2.1", + "version": "0.2.2", "description": "Open identity records for humans and AI agents", "type": "module", "main": "dist/src/index.js", diff --git a/src/mcp/index.ts b/src/mcp/index.ts index 43cb1be..92fd2b5 100644 --- a/src/mcp/index.ts +++ b/src/mcp/index.ts @@ -8,9 +8,20 @@ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { z } from "zod"; import { createIdentityStore, type IdentityStore } from "../storage.js"; +import { CloudHttpIdentityStore, resolveCloudHttpConfig } from "../http-store.js"; import { getPackageVersion } from "../version.js"; async function resolveStore(): Promise<{ store: IdentityStore; mode: "cloud" | "local"; close: () => Promise }> { + // Locked client architecture: when the self_hosted API env vars + // (HASNA_IDENTITIES_API_URL + HASNA_IDENTITIES_API_KEY) are set, route ALL + // reads/writes to the cloud `/v1` HTTP API with the bearer key. No DSN on the + // client. Unsetting the vars restores the local store. + const cloud = resolveCloudHttpConfig(); + if (cloud) { + return { store: new CloudHttpIdentityStore(cloud), mode: "cloud", close: async () => {} }; + } + // Legacy in-VPC server path: raw Postgres DSN is only ever used by the serve + // process (in-VPC), never distributed to client machines. const mode = (process.env["HASNA_IDENTITIES_STORAGE_MODE"] ?? "local").toLowerCase(); if (mode === "cloud") { // Lazy import so the local path never loads pg.