mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-30 13:20:54 +01:00
fix(mcp): cover assistant setup integration contracts
Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
1 parent
c1f1342a96
commit
797fecd803
3 files changed
+31
-6
No files matched your search
@@ -1666,7 +1666,7 @@ function resolveOperationAuthLevel(
|
||||
): OpenApiAuthLevel {
|
||||
const key = operationKey(method, path);
|
||||
if (key === "GET /api/mcp/requests/{id}") return "public";
|
||||
if (path.startsWith("/api/mcp/requests/") || path.startsWith("/api/mcp/connections")) return "board";
|
||||
if (path === "/api/mcp/setup" || path.startsWith("/api/mcp/requests/") || path.startsWith("/api/mcp/connections")) return "board";
|
||||
if (PUBLIC_OPERATIONS.has(key)) return "public";
|
||||
if (key === "POST /api/mcp/project-tools" || key === "POST /api/companies/{companyId}/slack/tasks/{issueId}/tools") return "agent_run";
|
||||
if (RUNTIME_TOOLS_OPERATIONS.has(key)) return "runtime_tools";
|
||||
@@ -11334,6 +11334,16 @@ registerCurrentRoute({
|
||||
},
|
||||
});
|
||||
|
||||
registerCurrentRoute({
|
||||
method: "get", path: "/api/mcp/setup", tags: ["tool-gateway"],
|
||||
summary: "Read assistant connection setup for a signed-in person",
|
||||
description: "Returns the live experimental setting and canonical MCP server URL. Requires a human browser session; agent and board API keys are not accepted. Remains available while the experiment is disabled and grants no access.",
|
||||
responses: {
|
||||
200: r.ok(z.object({ enabled: z.boolean(), serverUrl: z.string().url() })),
|
||||
401: r.unauthorized, 403: r.forbidden, 404: r.notFound,
|
||||
},
|
||||
});
|
||||
|
||||
registerCurrentRoute({
|
||||
method: "get", path: "/api/mcp/requests/{id}", tags: ["tool-gateway"],
|
||||
summary: "Describe an assistant connection request and available sign-in options",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// @vitest-environment jsdom
|
||||
|
||||
import { flushSync } from "react-dom";
|
||||
import { MemoryRouter } from "react-router-dom";
|
||||
import { createRoot, type Root } from "react-dom/client";
|
||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||
import { INSTANCE_FEATURE_KEYS } from "@paperclipai/shared";
|
||||
@@ -21,6 +22,10 @@ vi.mock("@/api/instanceSettings", () => ({
|
||||
instanceSettingsApi: mockInstanceSettingsApi,
|
||||
}));
|
||||
|
||||
vi.mock("@/context/CompanyContext", () => ({
|
||||
useCompany: () => ({ selectedCompany: { id: "butter", issuePrefix: "BUT" } }),
|
||||
}));
|
||||
|
||||
vi.mock("../context/BreadcrumbContext", () => ({
|
||||
useBreadcrumbs: () => ({ setBreadcrumbs: vi.fn() }),
|
||||
}));
|
||||
@@ -165,7 +170,9 @@ describe("InstanceExperimentalSettings — Conference Room Chat card (PAP-11233)
|
||||
flushSync(() => {
|
||||
root!.render(
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<InstanceExperimentalSettings />
|
||||
<MemoryRouter initialEntries={["/BUT/company/settings/instance/experimental"]}>
|
||||
<InstanceExperimentalSettings />
|
||||
</MemoryRouter>
|
||||
</QueryClientProvider>,
|
||||
);
|
||||
});
|
||||
@@ -242,6 +249,7 @@ describe("InstanceExperimentalSettings — Conference Room Chat card (PAP-11233)
|
||||
await flushReact();
|
||||
expect(mockInstanceSettingsApi.updateExperimental).toHaveBeenLastCalledWith({ enablePublicMcp: enabled });
|
||||
expect(container.querySelector(selector)?.getAttribute("aria-checked")).toBe(String(enabled));
|
||||
expect(Boolean(container.querySelector('a[href="/BUT/apps/assistant-connection"]'))).toBe(enabled);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -784,7 +792,9 @@ describe("InstanceExperimentalSettings — cloud-managed keys", () => {
|
||||
flushSync(() => {
|
||||
root!.render(
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<InstanceExperimentalSettings />
|
||||
<MemoryRouter initialEntries={["/BUT/company/settings/instance/experimental"]}>
|
||||
<InstanceExperimentalSettings />
|
||||
</MemoryRouter>
|
||||
</QueryClientProvider>,
|
||||
);
|
||||
});
|
||||
@@ -937,7 +947,9 @@ describe("InstanceExperimentalSettings — card ordering and headings (PAP-393)"
|
||||
flushSync(() => {
|
||||
root!.render(
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<InstanceExperimentalSettings />
|
||||
<MemoryRouter initialEntries={["/BUT/company/settings/instance/experimental"]}>
|
||||
<InstanceExperimentalSettings />
|
||||
</MemoryRouter>
|
||||
</QueryClientProvider>,
|
||||
);
|
||||
});
|
||||
@@ -1052,7 +1064,9 @@ describe("InstanceExperimentalSettings — operator-hidden cards", () => {
|
||||
flushSync(() => {
|
||||
root!.render(
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<InstanceExperimentalSettings />
|
||||
<MemoryRouter initialEntries={["/BUT/company/settings/instance/experimental"]}>
|
||||
<InstanceExperimentalSettings />
|
||||
</MemoryRouter>
|
||||
</QueryClientProvider>,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@ import { ApiError } from "@/api/client";
|
||||
import { useCompany } from "@/context/CompanyContext";
|
||||
import { useBreadcrumbs } from "@/context/BreadcrumbContext";
|
||||
import { Link } from "@/lib/router";
|
||||
import { copyTextToClipboard } from "@/lib/clipboard";
|
||||
import { CompanyPatternIcon } from "@/components/CompanyPatternIcon";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Tabs, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||
@@ -60,7 +61,7 @@ function CopyValue({ value, label }: { value: string; label: string }) {
|
||||
<div className="flex items-start gap-3 rounded-md border border-border bg-muted/30 p-3">
|
||||
<pre className="min-w-0 flex-1 overflow-x-auto whitespace-pre-wrap break-words font-mono text-xs leading-relaxed">{value}</pre>
|
||||
<Button type="button" variant="ghost" size="icon" className="size-8 shrink-0" aria-label={`Copy ${label}`} onClick={async () => {
|
||||
try { await navigator.clipboard.writeText(value); setCopied(true); setError(false); }
|
||||
try { await copyTextToClipboard(value); setCopied(true); setError(false); }
|
||||
catch { setError(true); }
|
||||
}}>{copied ? <Check className="size-4" /> : <Copy className="size-4" />}</Button>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user