Skip to content

Commit 041b8ca

Browse files
RhysSullivanbaggiiiie
authored andcommitted
Test OAuth metadata through connection and tool use
1 parent 91b2416 commit 041b8ca

1 file changed

Lines changed: 39 additions & 2 deletions

File tree

e2e/selfhost/mcp-oauth-cimd-connect.test.ts

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import { visit } from "../src/surfaces/browser";
2020
const api = composePluginApi([mcpHttpPlugin()] as const);
2121

2222
scenario(
23-
"MCP OAuth · advertised CIMD starts authorization without dynamic registration",
23+
"MCP OAuth · CIMD advertises refresh support and completes connection without dynamic registration",
2424
{ timeout: 180_000 },
2525
Effect.scoped(
2626
Effect.gen(function* () {
@@ -89,11 +89,48 @@ scenario(
8989
).toMatchObject({
9090
grant_types: ["authorization_code", "refresh_token"],
9191
});
92-
await popup.close();
92+
expect(authorize).toBeDefined();
93+
// oxlint-disable-next-line executor/no-try-catch-or-throw, executor/no-error-constructor -- test boundary: authorization must exist before completing the flow
94+
if (authorize === undefined) throw new Error("Missing authorization request");
95+
const completed = await Effect.runPromise(
96+
oauth.completeAuthorizationCodeFlow({ authorizationUrl: authorize.url }),
97+
);
98+
await popup.goto(completed.callbackUrl);
99+
await page
100+
.getByRole("heading", { name: /Add connection/ })
101+
.waitFor({ state: "hidden" });
102+
await popup.close().catch(() => undefined);
93103
});
94104
});
95105

106+
const connections = yield* client.connections.list({ query: { integration: slug } });
107+
expect(connections, "the OAuth callback saved the connection").toHaveLength(1);
108+
const tools = yield* client.tools.list({ query: { integration: slug } });
109+
expect(
110+
tools.some((tool) => tool.name === "simple_echo"),
111+
"authenticated discovery finds the upstream tool",
112+
).toBe(true);
113+
114+
const invoked = yield* client.executions.execute({
115+
payload: {
116+
code: `return await ${tools[0]?.address}({});`,
117+
autoApprove: true,
118+
},
119+
});
120+
expect(invoked.status).toBe("completed");
121+
expect(invoked.text, "the connected tool runs through authenticated MCP").toContain(
122+
"mcp-ok",
123+
);
124+
96125
const requests = yield* oauth.requests;
126+
expect(
127+
requests.some(
128+
(request) =>
129+
request.path === "/token" &&
130+
new URLSearchParams(request.body).get("grant_type") === "authorization_code",
131+
),
132+
"the callback exchanged the code using the advertised client",
133+
).toBe(true);
97134
expect(
98135
requests.filter((request) => request.method === "POST" && request.path === "/register"),
99136
"CIMD wins when the server also advertises DCR",

0 commit comments

Comments
 (0)