Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 16 additions & 1 deletion src/api/handlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1503,7 +1503,22 @@ export async function handleOidcRefresh(

return res;
} catch (err) {
console.error("[nimblebrain] Token refresh failed:", err);
// invalid_grant = refresh token expired/revoked (e.g. session ended due to
// inactivity). Expected; the client re-authenticates. Log terse, no stack.
// Anything else is unexpected — log the message (still no bundled-source dump).
const expired =
typeof err === "object" &&
err !== null &&
"error" in err &&
(err as { error?: unknown }).error === "invalid_grant";
if (expired) {
console.warn(
"[nimblebrain] Token refresh rejected (session expired) — client will re-authenticate",
);
} else {
const reason = err instanceof Error ? err.message : String(err);
console.error("[nimblebrain] Token refresh failed:", reason);
}
return apiError(401, "refresh_failed", "Token refresh failed");
}
}
Expand Down
30 changes: 2 additions & 28 deletions src/connectors/catalog.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
# before it leaves the registry.
#
# `_meta["ai.nimblebrain/connector"]` carries platform-specific fields
# that don't fit upstream-defined slots (defaultBinding, OAuth flow type,
# operator-setup pointer, recommended scopes, search tags, UI hints).
# that don't fit upstream-defined slots (OAuth flow type, operator-setup
# pointer, recommended scopes, search tags, UI hints).
#
# Operators with custom curation needs override this list at runtime by
# pointing `NB_REGISTRIES` at a JSON config that adds their own
Expand All @@ -32,7 +32,6 @@ servers:
url: https://mcp.asana.com/v2/mcp
_meta:
ai.nimblebrain/connector:
defaultBinding: workspace
auth: static
operatorSetup:
portalUrl: https://app.asana.com/0/my-apps
Expand All @@ -52,7 +51,6 @@ servers:
url: https://mcp.notion.com/mcp
_meta:
ai.nimblebrain/connector:
defaultBinding: workspace
auth: dcr
tags: [docs, knowledge]

Expand All @@ -68,7 +66,6 @@ servers:
url: https://mcp.linear.app/mcp
_meta:
ai.nimblebrain/connector:
defaultBinding: workspace
auth: dcr
tags: [issues, project-mgmt]

Expand All @@ -90,7 +87,6 @@ servers:
url: https://bindings.mcp.cloudflare.com/sse
_meta:
ai.nimblebrain/connector:
defaultBinding: workspace
auth: dcr
tags: [infra, devops]

Expand All @@ -112,7 +108,6 @@ servers:
url: https://mcp.dropbox.com/mcp
_meta:
ai.nimblebrain/connector:
defaultBinding: workspace
auth: static
requiredScopes:
- files.metadata.read
Expand Down Expand Up @@ -151,7 +146,6 @@ servers:
url: https://backend.composio.dev/v3/mcp
_meta:
ai.nimblebrain/connector:
defaultBinding: workspace
auth: composio
composio:
toolkit: gmail
Expand Down Expand Up @@ -206,7 +200,6 @@ servers:
url: https://backend.composio.dev/v3/mcp
_meta:
ai.nimblebrain/connector:
defaultBinding: workspace
auth: composio
composio:
toolkit: outlook
Expand Down Expand Up @@ -244,7 +237,6 @@ servers:
url: https://mcp.mercury.com/mcp
_meta:
ai.nimblebrain/connector:
defaultBinding: workspace
auth: dcr
tags: [banking, finance]

Expand All @@ -260,7 +252,6 @@ servers:
url: https://mcp.neon.tech/mcp
_meta:
ai.nimblebrain/connector:
defaultBinding: workspace
auth: dcr
tags: [database, postgres]

Expand All @@ -276,7 +267,6 @@ servers:
url: https://mcp.paypal.com/sse
_meta:
ai.nimblebrain/connector:
defaultBinding: workspace
auth: dcr
tags: [payments]

Expand All @@ -292,7 +282,6 @@ servers:
url: https://mcp.sentry.dev/mcp
_meta:
ai.nimblebrain/connector:
defaultBinding: workspace
auth: dcr
tags: [observability, errors]

Expand All @@ -308,7 +297,6 @@ servers:
url: https://mcp.stripe.com/
_meta:
ai.nimblebrain/connector:
defaultBinding: workspace
auth: dcr
tags: [payments, billing]

Expand All @@ -335,7 +323,6 @@ servers:
url: https://mcp.webflow.com/sse
_meta:
ai.nimblebrain/connector:
defaultBinding: workspace
auth: dcr
tags: [design, cms]

Expand All @@ -351,7 +338,6 @@ servers:
url: https://mcp.wix.com/sse
_meta:
ai.nimblebrain/connector:
defaultBinding: workspace
auth: dcr
tags: [website, cms]

Expand All @@ -367,7 +353,6 @@ servers:
url: https://mcp.granola.ai/mcp
_meta:
ai.nimblebrain/connector:
defaultBinding: workspace
auth: dcr
tags: [meetings, notes]

Expand All @@ -391,7 +376,6 @@ servers:
url: https://backend.composio.dev/v3/mcp
_meta:
ai.nimblebrain/connector:
defaultBinding: workspace
auth: composio
composio:
toolkit: box
Expand Down Expand Up @@ -426,7 +410,6 @@ servers:
url: https://backend.composio.dev/v3/mcp
_meta:
ai.nimblebrain/connector:
defaultBinding: workspace
auth: composio
composio:
toolkit: github
Expand Down Expand Up @@ -461,7 +444,6 @@ servers:
url: https://backend.composio.dev/v3/mcp
_meta:
ai.nimblebrain/connector:
defaultBinding: workspace
auth: composio
composio:
toolkit: googlecalendar
Expand Down Expand Up @@ -495,7 +477,6 @@ servers:
url: https://backend.composio.dev/v3/mcp
_meta:
ai.nimblebrain/connector:
defaultBinding: workspace
auth: composio
composio:
toolkit: quickbooks
Expand Down Expand Up @@ -531,7 +512,6 @@ servers:
url: https://backend.composio.dev/v3/mcp
_meta:
ai.nimblebrain/connector:
defaultBinding: workspace
auth: composio
composio:
toolkit: linkedin
Expand Down Expand Up @@ -566,7 +546,6 @@ servers:
url: https://backend.composio.dev/v3/mcp
_meta:
ai.nimblebrain/connector:
defaultBinding: workspace
auth: composio
composio:
toolkit: slack
Expand Down Expand Up @@ -601,7 +580,6 @@ servers:
url: https://backend.composio.dev/v3/mcp
_meta:
ai.nimblebrain/connector:
defaultBinding: workspace
auth: composio
composio:
toolkit: whatsapp
Expand Down Expand Up @@ -635,7 +613,6 @@ servers:
url: https://gmailmcp.googleapis.com/mcp/v1
_meta:
ai.nimblebrain/connector:
defaultBinding: personal
auth: static
requiredScopes:
- https://www.googleapis.com/auth/gmail.readonly
Expand All @@ -661,7 +638,6 @@ servers:
url: https://mcp.hubspot.com
_meta:
ai.nimblebrain/connector:
defaultBinding: personal
auth: static
operatorSetup:
portalUrl: https://developers.hubspot.com/docs/apps/developer-platform/build-apps/integrate-with-the-remote-hubspot-mcp-server
Expand All @@ -681,7 +657,6 @@ servers:
url: https://mcp.microsoft.com/mail
_meta:
ai.nimblebrain/connector:
defaultBinding: personal
auth: static
requiredScopes:
- https://graph.microsoft.com/Mail.ReadWrite
Expand All @@ -705,7 +680,6 @@ servers:
url: https://mcp.zoom.us/mcp
_meta:
ai.nimblebrain/connector:
defaultBinding: personal
auth: static
requiredScopes: [meeting:read, recording:read]
operatorSetup:
Expand Down
18 changes: 1 addition & 17 deletions src/connectors/server-detail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
* `MpakSource` reads the same shape natively from mpak's `/v1/servers/...`
* via the SDK. Consumers always see one type. The `_meta` extension
* `ai.nimblebrain/connector` carries our platform-specific fields
* (defaultBinding, auth, operatorSetup, etc.) without polluting
* upstream-defined slots.
* (auth, operatorSetup, etc.) without polluting upstream-defined slots.
*
* Validated at every system boundary so an invalid entry is dropped
* at the source it came from, never reaching the UI / agent. Each
Expand Down Expand Up @@ -106,21 +105,6 @@ export interface Package {
* it undefined).
*/
export interface NimbleBrainConnectorMeta {
/**
* Default install target — a UX hint the platform uses to decide
* which workspace receives the install action when the catalog entry
* is exercised.
*
* - `"workspace"` — install into the active workspace; bundle is
* shared with all members. Granted to admins only.
* - `"personal"` — install into the caller's personal workspace
* (`personalWorkspaceIdFor(userId)`); tokens are sole-owner by
* construction.
*
* Not a per-ref `oauthScope` — every installed ref is workspace-bound
* post-Stage-2. This field selects the wsId.
*/
defaultBinding?: "workspace" | "personal";
/**
* OAuth flow type for remote services.
*
Expand Down
4 changes: 0 additions & 4 deletions src/registries/projection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ export interface ProjectionContext {
* - `description` ← `ServerDetail.description`
* - `iconUrl` ← `ServerDetail.icons[0].src` (theme-aware picker is a follow-up)
* - `tags` ← `_meta.ai.nimblebrain/connector.tags`
* - `defaultBinding` ← `_meta.ai.nimblebrain/connector.defaultBinding` ?? `"workspace"`
* - `install` ← derived from `packages[]` (mpak-bundle) or `remotes[]` (remote-oauth)
*
* Returns null if the entry isn't installable (no packages, no remotes,
Expand All @@ -59,7 +58,6 @@ export function projectServerDetailToDirectoryEntry(
description: s.description,
...(iconUrl ? { iconUrl } : {}),
...(meta?.tags && meta.tags.length > 0 ? { tags: meta.tags } : {}),
defaultBinding: meta?.defaultBinding ?? "workspace",
install,
};
}
Expand Down Expand Up @@ -112,7 +110,6 @@ export interface ConnectorCatalogEntry {
/** Remote MCP server URL — the value that goes into the bundle `url`. */
url: string;
auth: "dcr" | "static" | "composio";
defaultBinding: "workspace" | "personal";
requiredScopes?: string[];
additionalAuthorizationParams?: Record<string, string>;
operatorSetup?: { portalUrl: string; hint: string; clientSecretKey: string };
Expand Down Expand Up @@ -149,7 +146,6 @@ export function serverDetailToCatalogEntry(s: ServerDetail): ConnectorCatalogEnt
iconUrl,
url: remote.url,
auth: meta?.auth ?? "dcr",
defaultBinding: meta?.defaultBinding ?? "workspace",
...(meta?.requiredScopes ? { requiredScopes: meta.requiredScopes } : {}),
...(meta?.additionalAuthorizationParams
? { additionalAuthorizationParams: meta.additionalAuthorizationParams }
Expand Down
6 changes: 0 additions & 6 deletions src/registries/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,6 @@ export interface DirectoryEntry {
description: string;
iconUrl?: string;
tags?: string[];
/**
* Default install target. UI uses this to filter Personal vs Workspace
* browse. `"workspace"` installs into the active workspace; `"personal"`
* installs into the caller's personal workspace.
*/
defaultBinding: "personal" | "workspace";
install: InstallAction;
/**
* For static-auth entries: whether the workspace has operator OAuth
Expand Down
Loading