feat(mcp): identity-via-arg + plugin ships .mcp.json
MCP tools (send/check_inbox/peek_inbox/list_mailboxes) now accept the caller's mailbox name as an explicit argument (from/name), falling back to the X-Mailbox header for legacy single-session HTTP setups. This unblocks multi-session coordination through a shared .mcp.json — each Claude session passes its own session-derived name on every call, instead of relying on a single transport header that all sessions would share. The plugin now ships .mcp.json (no header), and the SessionStart announcement spells out the exact args to pass to each mcp__mailbox__* tool so Claude wires it up automatically.
This commit is contained in:
44
node/tests/mcp.test.ts
Normal file
44
node/tests/mcp.test.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { resolveIdentity } from "../src/mcp.js";
|
||||
|
||||
function fakeExtra(header?: string): unknown {
|
||||
if (header === undefined) return {};
|
||||
return { requestInfo: { headers: { "x-mailbox": header } } };
|
||||
}
|
||||
|
||||
describe("resolveIdentity", () => {
|
||||
it("prefers the explicit argument when present", () => {
|
||||
expect(resolveIdentity("alice", fakeExtra("bob"), "from")).toBe("alice");
|
||||
});
|
||||
|
||||
it("falls back to X-Mailbox header when arg missing", () => {
|
||||
expect(resolveIdentity(undefined, fakeExtra("bob"), "from")).toBe("bob");
|
||||
});
|
||||
|
||||
it("trims whitespace from explicit arg and header", () => {
|
||||
expect(resolveIdentity(" alice ", fakeExtra(), "from")).toBe("alice");
|
||||
expect(resolveIdentity(undefined, fakeExtra(" bob "), "name")).toBe("bob");
|
||||
});
|
||||
|
||||
it("treats empty arg as missing and falls back", () => {
|
||||
expect(resolveIdentity("", fakeExtra("bob"), "name")).toBe("bob");
|
||||
expect(resolveIdentity(" ", fakeExtra("bob"), "name")).toBe("bob");
|
||||
});
|
||||
|
||||
it("throws with a helpful message when neither is provided", () => {
|
||||
expect(() => resolveIdentity(undefined, fakeExtra(), "from")).toThrow(
|
||||
/Pass `from`.*SessionStart announcement/i,
|
||||
);
|
||||
});
|
||||
|
||||
it("throws referencing the correct arg name", () => {
|
||||
expect(() => resolveIdentity(undefined, fakeExtra(), "name")).toThrow(
|
||||
/Pass `name`/,
|
||||
);
|
||||
});
|
||||
|
||||
it("handles extra without requestInfo", () => {
|
||||
expect(() => resolveIdentity(undefined, {}, "from")).toThrow(/Pass `from`/);
|
||||
expect(() => resolveIdentity(undefined, null, "from")).toThrow(/Pass `from`/);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user