Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
07c1908
Add ask MCP server integration
jsourcebot Mar 28, 2026
48b4448
Merge MCP user server credentials
jsourcebot May 22, 2026
c357e62
Inject Prisma into MCP OAuth provider
jsourcebot May 22, 2026
1e3fdc1
Scope MCP user server queries
jsourcebot May 22, 2026
da3f885
Add org-approved MCP servers
jsourcebot May 24, 2026
acda402
feat(web): add workspace MCP configuration
jsourcebot May 25, 2026
ffe0d87
fix(web): allow MCP cleanup without OAuth entitlement
jsourcebot May 25, 2026
1e6860b
feat(web): improve MCP server add flow
jsourcebot May 26, 2026
d193ce6
fix(web): check DCR for prefab MCP servers
jsourcebot May 26, 2026
820ecb3
feat(web): support static OAuth MCP credentials
jsourcebot May 26, 2026
95e2d95
feat(web): add more prefab MCP servers
jsourcebot May 26, 2026
e71e25f
fix(web): use official Atlassian MCP icons
jsourcebot May 26, 2026
d7e1e7d
fix(web): use Atlassian prefab MCP server
jsourcebot May 26, 2026
0abe155
feat(web): connect approved MCP servers from chat
jsourcebot May 26, 2026
4d1bcfc
feat(web): redesign MCP servers settings page
jsourcebot May 26, 2026
78cd0f0
Rename MCP settings to Ask Agent connectors
jsourcebot May 26, 2026
c0e9225
feat(web): redesign workspace Ask Agent settings page
jsourcebot May 27, 2026
29edd6c
feat(web): add workspace connector config link to chat toolbar
jsourcebot May 27, 2026
49d5906
Add MCP connector tool metadata
jsourcebot May 27, 2026
ff6fb0f
feat(web): redesign MCP tools list as compact clickable badges
jsourcebot May 27, 2026
33e7785
refactor(web): extract shared ConnectorCard component
jsourcebot May 27, 2026
0c72b28
Fix Ask approval turn progress state
jsourcebot May 27, 2026
289bf5c
Add MCP connector usage counters
jsourcebot May 28, 2026
5fc2fc8
Address MCP review feedback
jsourcebot May 28, 2026
25dae4e
Remove workspace Ask Agent connector summary cards
jsourcebot May 28, 2026
f358378
Add PostHog prefab MCP server
jsourcebot May 28, 2026
6d336f7
Add Ask MCP PostHog metrics
jsourcebot May 28, 2026
0bebd3b
Add Ask MCP tool call analytics
jsourcebot May 28, 2026
a62a615
Add Ask MCP connector lifecycle analytics
jsourcebot May 28, 2026
1d62399
Fix v5 rebase follow-ups
jsourcebot May 29, 2026
8903390
Clean up Ask MCP deployment references
jsourcebot May 29, 2026
209da4d
Move EE MCP feature under chat
jsourcebot May 29, 2026
71c2893
Simplify static MCP OAuth HTTPS guard
jsourcebot May 29, 2026
9c15807
docs: v5 docs updates (#1244)
msukkari May 29, 2026
6739694
[v5] feat(web): Add usage information for yearly subs (#1245)
brendan-kellam May 29, 2026
3d00a39
fix build errors after merge
msukkari May 29, 2026
2c34b08
fix bug where Ask doesn't load if we dont have a license key
msukkari May 29, 2026
33e702c
feat(web): gate MCP server behind paid subscription
msukkari May 30, 2026
8e69633
chore: fill in PR number in CHANGELOG
msukkari May 30, 2026
92255df
Merge remote-tracking branch 'origin/v5' into v5-ee
msukkari May 30, 2026
017c5eb
chore(db): remove MCP migrations from this branch
msukkari May 30, 2026
8f356f4
chore: remove CHANGELOG entry
msukkari May 30, 2026
c14dc14
feat(web): hide Chats sidebar item without the ask entitlement
msukkari May 30, 2026
ad2d797
refactor(web): relocate Ask connector OAuth code to the connector folder
msukkari May 30, 2026
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
157 changes: 0 additions & 157 deletions .github/workflows/release-mcp.yml

This file was deleted.

4 changes: 0 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,6 @@ Standard dev commands are documented in `CONTRIBUTING.md` and `package.json`. Ke
- **Build deps only:** `yarn build:deps` (builds shared packages: schemas, db, shared, query-language)
- **DB migrations:** `yarn dev:prisma:migrate:dev`

### Deprecated Packages

- **`packages/mcp`** - This standalone MCP package is deprecated. Do NOT modify it. MCP functionality is now handled by the web package at `packages/web/src/features/mcp/`.

### Non-obvious Caveats

- **Docker must be running** before `yarn dev`. Start it with `docker compose -f docker-compose-dev.yml up -d`. The backend will fail to connect to Redis/PostgreSQL otherwise.
Expand Down
1 change: 0 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -1020,7 +1020,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added
- Added audit logging. [#355](https://github.com/sourcebot-dev/sourcebot/pull/355)
<!-- @NOTE: this release includes a API change that affects the MCP package (@sourcebot/mcp). On release, bump the MCP package's version and delete this message. -->

### Fixed
- Delete account join request when redeeming an invite. [#352](https://github.com/sourcebot-dev/sourcebot/pull/352)
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ Then restart the dev server. Components that re-render will be highlighted in th
- Keep pull requests small and focused
- Explain the issue and why your change fixes it
- Before adding new functionality, ensure it doesn't already exist elsewhere in the codebase
- Update `CHANGELOG.md` with an entry under `[Unreleased]` linking to your PR. New entries should be placed at the bottom of their section. If your change touches `packages/mcp`, update `packages/mcp/CHANGELOG.md` instead.
- Update `CHANGELOG.md` with an entry under `[Unreleased]` linking to your PR. New entries should be placed at the bottom of their section.

### UI Changes

Expand Down
2 changes: 0 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ clean:
packages/db/dist \
packages/schemas/node_modules \
packages/schemas/dist \
packages/mcp/node_modules \
packages/mcp/dist \
packages/shared/node_modules \
packages/shared/dist \
.sourcebot
Expand Down
4 changes: 3 additions & 1 deletion docs/docs/features/mcp-server.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import LicenseKeyRequired from '/snippets/license-key-required.mdx'

The Sourcebot MCP Server connects AI tools to your [Sourcebot deployment](/docs/deployment/docker-compose). This gives your agents the ability to search, read files, resolve references & definitions, and more across all of your code hosted on Sourcebot.

<LicenseKeyRequired feature="The Sourcebot MCP server" />

## Use cases

- **Context for local agents:** Plug the MCP into coding agents like Cursor, Claude Code, or Copilot to give them context across your entire codebase, not just the open workspace.
Expand All @@ -16,7 +18,7 @@ The Sourcebot MCP Server connects AI tools to your [Sourcebot deployment](/docs/

Sourcebot MCP uses a [Streamable HTTP](https://modelcontextprotocol.io/specification/2025-06-18/basic/transports#streamable-http) transport hosted at the `/api/mcp` route. Two authorization mechanisms are supported:

- **OAuth (preferred)**: MCP clients that support OAuth 2.0 will automatically handle the authorization flow and issue a short lived access token. No API key or manual token management required. Only available with an active [Enterprise license](/docs/activating-a-subscription).
- **OAuth (preferred)**: MCP clients that support OAuth 2.0 will automatically handle the authorization flow and issue a short lived access token. No API key or manual token management required. Only available with a paid [subscription](/docs/activating-a-subscription).
- **API key**: Any MCP client can authorize using a Sourcebot API key passed as a `Authorization: Bearer <key>` header. Create one in **Settings → API Keys**.

You can read more about the options in the [authorization](#authorization) section.
Expand Down
4 changes: 2 additions & 2 deletions packages/shared/src/entitlements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@ const ALL_ENTITLEMENTS = [
"analytics",
"permission-syncing",
"github-app",
"chat-sharing",
"org-management",
"oauth",
"ask"
"ask",
"mcp"
] as const;
export type Entitlement = (typeof ALL_ENTITLEMENTS)[number];

Expand Down
7 changes: 7 additions & 0 deletions packages/web/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ const nextConfig = {
{
source: "/register",
destination: "/api/ee/oauth/register",
},
// The MCP server lives under /api/ee/mcp so it sits in the EE-licensed
// route tree, but is exposed at the stable, public /api/mcp path that
// existing MCP client configurations point at.
{
source: "/api/mcp",
destination: "/api/ee/mcp",
}
];
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { ChatHistory } from "./chatHistory";
import { RepoVisitHistory } from "./repoVisitHistory";
import { getAuthContext, withAuth } from "@/middleware/withAuth";
import { sew } from "@/middleware/sew";
import { isValidLicenseActive } from "@/lib/entitlements";
import { hasEntitlement, isValidLicenseActive } from "@/lib/entitlements";

const SIDEBAR_CHAT_LIMIT = 30;
export const SIDEBAR_REPO_VISITS_LIMIT = 10;
Expand All @@ -23,7 +23,10 @@ export async function DefaultSidebar() {
const cookieStore = await cookies();
const homeView = (cookieStore.get(HOME_VIEW_COOKIE_NAME)?.value ?? "search") as HomeView;

const chatHistory = session ? await getUserChatHistory() : [];
// Chat history is part of the Ask experience; hide it when the deployment
// is not on a plan that includes Ask.
const hasAskEntitlement = await hasEntitlement('ask');
const chatHistory = (session && hasAskEntitlement) ? await getUserChatHistory() : [];
if (isServiceError(chatHistory)) {
throw new ServiceErrorException(chatHistory);
}
Expand Down Expand Up @@ -63,10 +66,12 @@ export async function DefaultSidebar() {
}
>
<RepoVisitHistory repoVisits={repoVisits} />
<ChatHistory
chatHistory={chatHistory.slice(0, SIDEBAR_CHAT_LIMIT)}
hasMore={chatHistory.length > SIDEBAR_CHAT_LIMIT}
/>
{hasAskEntitlement && (
<ChatHistory
chatHistory={chatHistory.slice(0, SIDEBAR_CHAT_LIMIT)}
hasMore={chatHistory.length > SIDEBAR_CHAT_LIMIT}
/>
)}
</SidebarBase>
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ interface NavItem {
key: string;
requiresAuth?: boolean;
requiredEntitlement?: Entitlement;
// When true, the item is hidden entirely if the required entitlement is
// missing, instead of being shown with an upgrade badge.
hideIfMissingEntitlement?: boolean;
}

interface NavProps {
Expand Down Expand Up @@ -69,6 +72,8 @@ export function Nav({
icon: MessagesSquareIcon,
key: "chats",
requiresAuth: true,
requiredEntitlement: "ask",
hideIfMissingEntitlement: true,
},
{
title: "Repositories",
Expand Down Expand Up @@ -108,7 +113,10 @@ export function Nav({

return (
<SidebarMenu>
{baseItems.filter((item) => !item.requiresAuth || isSignedIn).map((item) => {
{baseItems
.filter((item) => !item.requiresAuth || isSignedIn)
.filter((item) => !item.hideIfMissingEntitlement || !item.requiredEntitlement || entitlements.includes(item.requiredEntitlement))
.map((item) => {
const showNotification =
(item.key === "settings" && isSettingsNotificationVisible);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import { ArrowUpCircle } from "lucide-react";
import { useState } from "react";
import { UpsellDialog } from "@/ee/features/lighthouse/upsellDialog";
import { useOffers } from "@/ee/features/lighthouse/useOffers";
import { UpsellDialog } from "@/features/billing/upsellDialog";
import { useOffers } from "@/features/billing/useOffers";
import { Skeleton } from "@/components/ui/skeleton";

export const UpgradeButton = () => {
Expand Down
8 changes: 8 additions & 0 deletions packages/web/src/app/(app)/askgh/[owner]/[repo]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { RepoIndexedGuard } from "./components/repoIndexedGuard";
import { LandingPage } from "./components/landingPage";
import { getConfiguredLanguageModelsInfo } from "@/features/chat/utils.server";
import { auth } from "@/auth";
import { hasEntitlement } from "@/lib/entitlements";
import { ChatEntitlementMessage } from "@/features/chat/components/chatEntitlementMessage";

interface PageProps {
params: Promise<{ owner: string; repo: string }>;
Expand All @@ -17,6 +19,12 @@ export default async function GitHubRepoPage(props: PageProps) {
const params = await props.params;
const { owner, repo } = params;
const session = await auth();

// The askgh experiment env flag must never bypass licensing; enforce `ask`
// uniformly (the demo deployment carries a real license with `ask`).
if (!await hasEntitlement('ask')) {
return <ChatEntitlementMessage source="chat" returnPath={`/askgh/${owner}/${repo}`} />;
}

const repoId = await (async () => {
// 1. Look up repo by owner/repo
Expand Down
21 changes: 19 additions & 2 deletions packages/web/src/app/(app)/chat/[id]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { getChatInfo, getSharedWithUsersForChat } from '@/features/chat/actions'
import { getConfiguredLanguageModelsInfo } from "@/features/chat/utils.server";
import { ServiceErrorException } from '@/lib/serviceError';
import { isServiceError } from '@/lib/utils';
import { ChatThreadPanel } from './components/chatThreadPanel';
import { ChatThreadPanel } from '@/ee/features/chat/components/chatThreadPanel';
import { notFound } from 'next/navigation';
import { StatusCodes } from 'http-status-codes';
import { Separator } from '@/components/ui/separator';
Expand All @@ -16,6 +16,7 @@ import { Metadata } from 'next';
import { SBChatMessage } from '@/features/chat/types';
import { env } from '@sourcebot/shared';
import { hasEntitlement } from '@/lib/entitlements';
import { ChatEntitlementMessage } from '@/features/chat/components/chatEntitlementMessage';
import { captureEvent } from '@/lib/posthog';

interface PageProps {
Expand Down Expand Up @@ -81,6 +82,20 @@ export default async function Page(props: PageProps) {
const params = await props.params;
const session = await auth();

// Gate the Ask experience behind the `ask` entitlement (deployment-level).
// Viewing a public/shared chat still works on a licensed deployment; a
// downgraded deployment shows the upsell while preserving the chat data.
if (!await hasEntitlement('ask')) {
return (
<ChatEntitlementMessage
source="chat"
returnPath={`/chat/${params.id}`}
title="Upgrade to view this Ask Sourcebot chat"
description="Pick up this conversation right where you left off."
/>
);
}

const languageModels = await getConfiguredLanguageModelsInfo();
const repos = await getRepos();
const searchContexts = await getSearchContexts();
Expand Down Expand Up @@ -122,7 +137,9 @@ export default async function Page(props: PageProps) {

const indexedRepos = repos.filter((repo) => repo.indexedAt !== undefined);

const hasChatSharingEntitlement = await hasEntitlement('chat-sharing');
// Chat sharing is part of Ask (the standalone `chat-sharing` entitlement was
// folded into `ask`). By this point the page is already gated on `ask`.
const hasChatSharingEntitlement = await hasEntitlement('ask');

return (
<div className="flex flex-col h-full">
Expand Down
2 changes: 1 addition & 1 deletion packages/web/src/app/(app)/chats/chatsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useHotkeys } from "react-hotkeys-hook";

import { listChats } from "@/app/api/(client)/client";
import type { ListChatsResponse } from "@/app/api/(server)/chats/types";
import type { ListChatsResponse } from "@/app/api/(server)/ee/chats/types";

type Chat = ListChatsResponse["chats"][number];
type SortBy = "name" | "updatedAt";
Expand Down
Loading
Loading