@intentface/latch-mcp 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +25 -0
- package/dist/approval.test.d.ts +2 -0
- package/dist/approval.test.d.ts.map +1 -0
- package/dist/approval.test.js +64 -0
- package/dist/approval.test.js.map +1 -0
- package/dist/connections.d.ts +180 -0
- package/dist/connections.d.ts.map +1 -0
- package/dist/connections.js +255 -0
- package/dist/connections.js.map +1 -0
- package/dist/host-output.test.d.ts +2 -0
- package/dist/host-output.test.d.ts.map +1 -0
- package/dist/host-output.test.js +51 -0
- package/dist/host-output.test.js.map +1 -0
- package/dist/host.d.ts +203 -0
- package/dist/host.d.ts.map +1 -0
- package/dist/host.js +259 -0
- package/dist/host.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +12 -0
- package/dist/index.js.map +1 -0
- package/dist/oauth-fetch.d.ts +45 -0
- package/dist/oauth-fetch.d.ts.map +1 -0
- package/dist/oauth-fetch.js +106 -0
- package/dist/oauth-fetch.js.map +1 -0
- package/dist/oauth.d.ts +120 -0
- package/dist/oauth.d.ts.map +1 -0
- package/dist/oauth.js +202 -0
- package/dist/oauth.js.map +1 -0
- package/dist/oauth.test.d.ts +2 -0
- package/dist/oauth.test.d.ts.map +1 -0
- package/dist/oauth.test.js +211 -0
- package/dist/oauth.test.js.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { describe, expect, it, vi, beforeEach } from "vitest";
|
|
2
|
+
/**
|
|
3
|
+
* `scope` may be a function, resolved per caller at flow time.
|
|
4
|
+
*
|
|
5
|
+
* This is a correctness requirement rather than API sugar: a single `McpOAuth`
|
|
6
|
+
* is shared across callers (UI-added connections are cached by connection
|
|
7
|
+
* NAME, while the connection record — and therefore its requested scopes —
|
|
8
|
+
* lives in each caller's own Vault). A static scope string would send one
|
|
9
|
+
* caller's scopes on another caller's authorize request, which for a
|
|
10
|
+
* *restriction* scope like Loredex's `private_only` means silently handing
|
|
11
|
+
* someone a broader grant than their connection asked for.
|
|
12
|
+
*/
|
|
13
|
+
const authMock = vi.hoisted(() => vi.fn());
|
|
14
|
+
vi.mock("@ai-sdk/mcp", () => ({
|
|
15
|
+
auth: authMock,
|
|
16
|
+
}));
|
|
17
|
+
const { createMcpOAuth, decodeOAuthState } = await import("./oauth.js");
|
|
18
|
+
/** Minimal in-memory Vault, keyed by principal so callers stay separate. */
|
|
19
|
+
function fakeVault() {
|
|
20
|
+
const store = new Map();
|
|
21
|
+
const k = (p, key) => `${p.userId}::${key}`;
|
|
22
|
+
return {
|
|
23
|
+
async set(p, key, value) {
|
|
24
|
+
store.set(k(p, key), value);
|
|
25
|
+
},
|
|
26
|
+
async get(p, key) {
|
|
27
|
+
return store.get(k(p, key));
|
|
28
|
+
},
|
|
29
|
+
async has(p, key) {
|
|
30
|
+
return store.has(k(p, key));
|
|
31
|
+
},
|
|
32
|
+
async delete(p, key) {
|
|
33
|
+
store.delete(k(p, key));
|
|
34
|
+
},
|
|
35
|
+
async list(p) {
|
|
36
|
+
return [...store.keys()].filter((x) => x.startsWith(`${p.userId}::`));
|
|
37
|
+
},
|
|
38
|
+
resolver: {},
|
|
39
|
+
_store: store,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
function build(scope, vault = fakeVault()) {
|
|
43
|
+
return {
|
|
44
|
+
vault,
|
|
45
|
+
oauth: createMcpOAuth({
|
|
46
|
+
vault: vault,
|
|
47
|
+
config: {
|
|
48
|
+
name: "loredex",
|
|
49
|
+
serverUrl: "https://loredex.example/ws/mcp",
|
|
50
|
+
redirectUrl: "https://latch.example/cb",
|
|
51
|
+
clientMetadata: {
|
|
52
|
+
client_name: "Latch (loredex)",
|
|
53
|
+
redirect_uris: ["https://latch.example/cb"],
|
|
54
|
+
},
|
|
55
|
+
scope: scope,
|
|
56
|
+
},
|
|
57
|
+
}),
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/** The `scope` value handed to the SDK on the most recent `start()`. */
|
|
61
|
+
const lastScope = () => authMock.mock.calls.at(-1)?.[1]?.scope;
|
|
62
|
+
beforeEach(() => {
|
|
63
|
+
authMock.mockReset();
|
|
64
|
+
authMock.mockResolvedValue("AUTHORIZED");
|
|
65
|
+
});
|
|
66
|
+
describe("createMcpOAuth scope resolution", () => {
|
|
67
|
+
it("passes a static scope through unchanged", async () => {
|
|
68
|
+
const { oauth } = build("private_only");
|
|
69
|
+
await oauth.start({ userId: "u1" });
|
|
70
|
+
expect(lastScope()).toBe("private_only");
|
|
71
|
+
});
|
|
72
|
+
it("omits the scope entirely when unset", async () => {
|
|
73
|
+
// Connections that request nothing must keep their previous, scope-less
|
|
74
|
+
// authorize request — adding an empty `scope=` would change the ask.
|
|
75
|
+
const { oauth } = build(undefined);
|
|
76
|
+
await oauth.start({ userId: "u1" });
|
|
77
|
+
expect(lastScope()).toBeUndefined();
|
|
78
|
+
});
|
|
79
|
+
it("resolves a function scope per caller", async () => {
|
|
80
|
+
// The core requirement: two callers of the SAME connection get their own
|
|
81
|
+
// scopes, because the record is per-caller while the client is shared.
|
|
82
|
+
const scopes = {
|
|
83
|
+
u1: "private_only",
|
|
84
|
+
u2: undefined,
|
|
85
|
+
};
|
|
86
|
+
const { oauth } = build((p) => scopes[p.userId]);
|
|
87
|
+
await oauth.start({ userId: "u1" });
|
|
88
|
+
expect(lastScope()).toBe("private_only");
|
|
89
|
+
await oauth.start({ userId: "u2" });
|
|
90
|
+
expect(lastScope()).toBeUndefined();
|
|
91
|
+
// ...and back again, so nothing was cached from the first resolution.
|
|
92
|
+
await oauth.start({ userId: "u1" });
|
|
93
|
+
expect(lastScope()).toBe("private_only");
|
|
94
|
+
});
|
|
95
|
+
it("awaits an async scope resolver", async () => {
|
|
96
|
+
// The real resolver reads the connection out of the Vault, so it is async.
|
|
97
|
+
const { oauth } = build(async (p) => p.userId === "u1" ? "mcp:read private_only" : undefined);
|
|
98
|
+
await oauth.start({ userId: "u1" });
|
|
99
|
+
expect(lastScope()).toBe("mcp:read private_only");
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
describe("authorizationParams", () => {
|
|
103
|
+
// Providers like Google need extra authorize params the SDK doesn't model
|
|
104
|
+
// (`access_type=offline&prompt=consent` for a refresh token). They are
|
|
105
|
+
// appended to the SDK-built redirect URL in start().
|
|
106
|
+
it("appends the configured params to the authorization URL", async () => {
|
|
107
|
+
const vault = fakeVault();
|
|
108
|
+
const oauth = createMcpOAuth({
|
|
109
|
+
vault: vault,
|
|
110
|
+
config: {
|
|
111
|
+
name: "gcal",
|
|
112
|
+
serverUrl: "https://calendarmcp.example/mcp/v1",
|
|
113
|
+
redirectUrl: "https://latch.example/cb",
|
|
114
|
+
clientMetadata: {
|
|
115
|
+
client_name: "Latch (gcal)",
|
|
116
|
+
redirect_uris: ["https://latch.example/cb"],
|
|
117
|
+
},
|
|
118
|
+
authorizationParams: { access_type: "offline", prompt: "consent" },
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
// Simulate the SDK asking for a browser redirect.
|
|
122
|
+
authMock.mockImplementationOnce(async (provider) => {
|
|
123
|
+
provider.redirectToAuthorization(new URL("https://idp.example/authorize?client_id=abc"));
|
|
124
|
+
return "REDIRECT";
|
|
125
|
+
});
|
|
126
|
+
const res = await oauth.start({ userId: "u1" });
|
|
127
|
+
if (res.status !== "redirect")
|
|
128
|
+
throw new Error("expected redirect");
|
|
129
|
+
const url = new URL(res.authorizationUrl);
|
|
130
|
+
expect(url.searchParams.get("client_id")).toBe("abc"); // SDK params kept
|
|
131
|
+
expect(url.searchParams.get("access_type")).toBe("offline");
|
|
132
|
+
expect(url.searchParams.get("prompt")).toBe("consent");
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
describe("state encoding", () => {
|
|
136
|
+
it("round-trips app context (incl. a pinned principal) through decodeOAuthState", async () => {
|
|
137
|
+
// The handler pins the resolved principal into the flow state at
|
|
138
|
+
// authorize time; the callback must recover it byte-for-byte.
|
|
139
|
+
const { oauth } = build(undefined);
|
|
140
|
+
const stateData = {
|
|
141
|
+
returnTo: "/chat/c1",
|
|
142
|
+
__latch: { p: { orgId: "org_a", userId: "u1" }, iat: 1_700_000_000_000 },
|
|
143
|
+
};
|
|
144
|
+
let sent;
|
|
145
|
+
authMock.mockImplementationOnce(async (provider) => {
|
|
146
|
+
sent = provider.state();
|
|
147
|
+
await provider.saveState(sent);
|
|
148
|
+
provider.redirectToAuthorization(new URL("https://idp.example/authorize"));
|
|
149
|
+
return "REDIRECT";
|
|
150
|
+
});
|
|
151
|
+
await oauth.start({ userId: "u1" }, { state: stateData });
|
|
152
|
+
expect(decodeOAuthState(sent)).toEqual(stateData);
|
|
153
|
+
});
|
|
154
|
+
it("returns undefined for a bare csrf or garbage", () => {
|
|
155
|
+
expect(decodeOAuthState("deadbeef")).toBeUndefined();
|
|
156
|
+
expect(decodeOAuthState("deadbeef.%%%not-b64%%%")).toBeUndefined();
|
|
157
|
+
expect(decodeOAuthState(null)).toBeUndefined();
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
describe("finish", () => {
|
|
161
|
+
it("deletes the spent state + verifier but keeps tokens/client/as_info", async () => {
|
|
162
|
+
// Single-use flow state: a replayed callback URL must find no stored flow
|
|
163
|
+
// material — while the durable credential parts survive.
|
|
164
|
+
const { vault, oauth } = build(undefined);
|
|
165
|
+
const p = { userId: "u1" };
|
|
166
|
+
for (const part of ["tokens", "verifier", "state", "client", "as_info"]) {
|
|
167
|
+
await vault.set(p, `mcp_oauth:loredex:${part}`, "x");
|
|
168
|
+
}
|
|
169
|
+
authMock.mockResolvedValueOnce("AUTHORIZED");
|
|
170
|
+
await oauth.finish(p, { code: "abc", state: "deadbeef" });
|
|
171
|
+
expect(await vault.has(p, "mcp_oauth:loredex:state")).toBe(false);
|
|
172
|
+
expect(await vault.has(p, "mcp_oauth:loredex:verifier")).toBe(false);
|
|
173
|
+
expect(await vault.has(p, "mcp_oauth:loredex:tokens")).toBe(true);
|
|
174
|
+
expect(await vault.has(p, "mcp_oauth:loredex:client")).toBe(true);
|
|
175
|
+
expect(await vault.has(p, "mcp_oauth:loredex:as_info")).toBe(true);
|
|
176
|
+
});
|
|
177
|
+
it("does not delete flow state when the exchange throws", async () => {
|
|
178
|
+
// A transient exchange failure must leave the flow re-tryable.
|
|
179
|
+
const { vault, oauth } = build(undefined);
|
|
180
|
+
const p = { userId: "u1" };
|
|
181
|
+
await vault.set(p, "mcp_oauth:loredex:state", "s");
|
|
182
|
+
await vault.set(p, "mcp_oauth:loredex:verifier", "v");
|
|
183
|
+
authMock.mockRejectedValueOnce(new Error("exchange failed"));
|
|
184
|
+
await expect(oauth.finish(p, { code: "abc", state: "s" })).rejects.toThrow();
|
|
185
|
+
expect(await vault.has(p, "mcp_oauth:loredex:state")).toBe(true);
|
|
186
|
+
expect(await vault.has(p, "mcp_oauth:loredex:verifier")).toBe(true);
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
describe("invalidateCredentials", () => {
|
|
190
|
+
it("clears the DCR client as well as the tokens", async () => {
|
|
191
|
+
// A scope change re-runs registration: the stored client was registered
|
|
192
|
+
// under the old scope, so keeping it would re-request the old grant.
|
|
193
|
+
const { vault, oauth } = build("private_only");
|
|
194
|
+
const p = { userId: "u1" };
|
|
195
|
+
for (const part of ["tokens", "verifier", "state", "client", "as_info"]) {
|
|
196
|
+
await vault.set(p, `mcp_oauth:loredex:${part}`, "x");
|
|
197
|
+
}
|
|
198
|
+
await oauth.provider(p).invalidateCredentials?.("all");
|
|
199
|
+
expect(await vault.list(p)).toEqual([]);
|
|
200
|
+
});
|
|
201
|
+
it("leaves another caller's tokens alone", async () => {
|
|
202
|
+
const { vault, oauth } = build("private_only");
|
|
203
|
+
const mine = { userId: "u1" };
|
|
204
|
+
const theirs = { userId: "u2" };
|
|
205
|
+
await vault.set(mine, "mcp_oauth:loredex:tokens", "mine");
|
|
206
|
+
await vault.set(theirs, "mcp_oauth:loredex:tokens", "theirs");
|
|
207
|
+
await oauth.provider(mine).invalidateCredentials?.("all");
|
|
208
|
+
expect(await vault.get(theirs, "mcp_oauth:loredex:tokens")).toBe("theirs");
|
|
209
|
+
});
|
|
210
|
+
});
|
|
211
|
+
//# sourceMappingURL=oauth.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"oauth.test.js","sourceRoot":"","sources":["../src/oauth.test.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@intentface/latch-mcp",
|
|
3
|
+
"version": "0.9.1",
|
|
4
|
+
"description": "Latch MCP host — connect to MCP servers as tools, with a per-tenant SSRF allowlist and vault-brokered auth.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"ai",
|
|
7
|
+
"ai-sdk",
|
|
8
|
+
"agents",
|
|
9
|
+
"llm",
|
|
10
|
+
"mcp",
|
|
11
|
+
"model-context-protocol",
|
|
12
|
+
"tools"
|
|
13
|
+
],
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"main": "./dist/index.js",
|
|
17
|
+
"module": "./dist/index.js",
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"import": "./dist/index.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist"
|
|
27
|
+
],
|
|
28
|
+
"sideEffects": false,
|
|
29
|
+
"publishConfig": {
|
|
30
|
+
"access": "public",
|
|
31
|
+
"registry": "https://registry.npmjs.org"
|
|
32
|
+
},
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"@intentface/latch-core": "^0.9.1",
|
|
35
|
+
"@intentface/latch-net": "^0.9.1"
|
|
36
|
+
},
|
|
37
|
+
"peerDependencies": {
|
|
38
|
+
"@ai-sdk/mcp": ">=2.0.0",
|
|
39
|
+
"ai": ">=7.0.0"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@ai-sdk/mcp": "^2.0.0",
|
|
43
|
+
"ai": "^7.0.2",
|
|
44
|
+
"typescript": "^5.7.0",
|
|
45
|
+
"vitest": "^4"
|
|
46
|
+
},
|
|
47
|
+
"repository": {
|
|
48
|
+
"type": "git",
|
|
49
|
+
"url": "git+https://github.com/Intentface/intentface-latch.git",
|
|
50
|
+
"directory": "packages/mcp"
|
|
51
|
+
},
|
|
52
|
+
"scripts": {
|
|
53
|
+
"build": "tsc -p tsconfig.json",
|
|
54
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
55
|
+
"test": "vitest run"
|
|
56
|
+
}
|
|
57
|
+
}
|