MCPcopy
hub / github.com/nowork-studio/NotFair / addUserMcpServerAction

Function addUserMcpServerAction

notfair-cmo/src/server/actions/mcp.ts:262–332  ·  view source on GitHub ↗
(input: {
  display_name: string;
  description?: string;
  resource_url: string;
  /** Optional canonical key override (used by Browse connectors). */
  key?: string;
})

Source from the content-addressed store, hash-verified

260 * `notfair-google-ads`). When omitted, the display name is slugified.
261 */
262export async function addUserMcpServerAction(input: {
263 display_name: string;
264 description?: string;
265 resource_url: string;
266 /** Optional canonical key override (used by Browse connectors). */
267 key?: string;
268}): Promise<AddUserMcpServerResult> {
269 const project = await getActiveProject();
270 if (!project) {
271 return {
272 ok: false,
273 kind: "no_project",
274 error: "No active project. Pick one before adding an MCP server.",
275 };
276 }
277
278 let key: string;
279 if (input.key && KEY_PATTERN.test(input.key)) {
280 key = input.key;
281 } else {
282 const slug = slugify(input.display_name);
283 if (!slug.ok) {
284 return {
285 ok: false,
286 kind: "name_unusable",
287 error: `Can't derive a key from this name: ${slug.reason}.`,
288 };
289 }
290 key = slug.slug;
291 }
292
293 // Preset re-add: just un-hide. No row to write, no discovery probe.
294 if (isPresetKey(key)) {
295 const { removeHiddenMcpPresetKey } = await import("@/server/db/projects");
296 removeHiddenMcpPresetKey(project.slug, key);
297 revalidatePath("/", "layout");
298 return { ok: true, key };
299 }
300
301 // User row already exists for this key — Browse "click again" path.
302 if (findUserMcpServer(project.slug, key)) {
303 return { ok: true, key };
304 }
305
306 // Same MCP server (same URL) is already in this project under a
307 // different key — e.g. NotFair Meta Ads was added pre-canonical-id and
308 // saved as `notfair-meta-ads`, while the tile click would use
309 // `notfair-metaads`. Treat as an idempotent re-pick: return the
310 // existing key so the connect chain reuses it instead of writing a
311 // duplicate row.
312 const existingByUrl = findUserMcpServerByResourceUrl(
313 project.slug,
314 input.resource_url,
315 );
316 if (existingByUrl) {
317 return { ok: true, key: existingByUrl.key };
318 }
319

Callers 3

onPickFunction · 0.90
onSubmitFunction · 0.90

Calls 8

getActiveProjectFunction · 0.90
slugifyFunction · 0.90
isPresetKeyFunction · 0.90
findUserMcpServerFunction · 0.90
insertUserMcpServerFunction · 0.90
removeHiddenMcpPresetKeyFunction · 0.85
probeMcpDiscoveryFunction · 0.85

Tested by

no test coverage detected