Browse Source

Setup MCP

pull/7703/head
Thomas Kaul 6 days ago
parent
commit
d5571e98ed
  1. 3
      apps/api/src/app/endpoints/mcp/mcp.controller.ts
  2. 5
      apps/api/src/app/endpoints/mcp/mcp.module.ts
  3. 6
      apps/api/src/main.ts
  4. 4
      apps/api/src/services/impersonation/impersonation.service.ts
  5. 3
      libs/common/src/lib/types/impersonation-context.type.ts

3
apps/api/src/app/endpoints/mcp/mcp.controller.ts

@ -27,9 +27,10 @@ export class GhostfolioMcpController {
name: 'get-portfolio' name: 'get-portfolio'
}) })
public async getPortfolio( public async getPortfolio(
@Impersonation() { userId, userSettings }: ImpersonationContext @Impersonation() { filters, userId, userSettings }: ImpersonationContext
) { ) {
const prompt = await this.aiService.getPrompt({ const prompt = await this.aiService.getPrompt({
filters,
userId, userId,
languageCode: userSettings.language ?? DEFAULT_LANGUAGE_CODE, languageCode: userSettings.language ?? DEFAULT_LANGUAGE_CODE,
mode: 'portfolio', mode: 'portfolio',

5
apps/api/src/app/endpoints/mcp/mcp.module.ts

@ -31,7 +31,10 @@ import { GhostfolioMcpController } from './mcp.controller';
transports: [ transports: [
new StreamableHttpTransport({ new StreamableHttpTransport({
endpoint: MCP_ENDPOINT, endpoint: MCP_ENDPOINT,
security: { allowedOrigins: [hostname] } security: {
allowedHosts: [hostname],
allowedOrigins: [hostname]
}
}) })
], ],
version: environment.version, version: environment.version,

6
apps/api/src/main.ts

@ -137,10 +137,8 @@ async function bootstrap() {
const PORT = configService.get<number>('PORT') || DEFAULT_PORT; const PORT = configService.get<number>('PORT') || DEFAULT_PORT;
if (configurationService.get('ENABLE_FEATURE_MCP')) { if (configurationService.get('ENABLE_FEATURE_MCP')) {
const rootUrl = configurationService.get('ROOT_URL'); if (!process.env.ROOT_URL) {
const { hostname } = new URL(configurationService.get('ROOT_URL'));
if (rootUrl === environment.rootUrl) {
const { hostname } = new URL(rootUrl);
logger.warn( logger.warn(
`The Model Context Protocol (MCP) is enabled, but ROOT_URL is not set. A client which calls the endpoint from a browser page is accepted only with the origin ${hostname}.` `The Model Context Protocol (MCP) is enabled, but ROOT_URL is not set. A client which calls the endpoint from a browser page is accepted only with the origin ${hostname}.`

4
apps/api/src/services/impersonation/impersonation.service.ts

@ -2,7 +2,7 @@ import { SubscriptionService } from '@ghostfolio/api/app/subscription/subscripti
import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service'; import { ConfigurationService } from '@ghostfolio/api/services/configuration/configuration.service';
import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service'; import { PrismaService } from '@ghostfolio/api/services/prisma/prisma.service';
import { DEFAULT_CURRENCY } from '@ghostfolio/common/config'; import { DEFAULT_CURRENCY } from '@ghostfolio/common/config';
import { UserSettings } from '@ghostfolio/common/interfaces'; import { AccessSettings, UserSettings } from '@ghostfolio/common/interfaces';
import { hasPermission, permissions } from '@ghostfolio/common/permissions'; import { hasPermission, permissions } from '@ghostfolio/common/permissions';
import { import {
getScopesOfAccess, getScopesOfAccess,
@ -63,9 +63,11 @@ export class ImpersonationService {
where: { id: impersonatedUserId } where: { id: impersonatedUserId }
}); });
const { filters } = (access?.settings ?? {}) as AccessSettings;
const settings = impersonatedUser?.settings?.settings as UserSettings; const settings = impersonatedUser?.settings?.settings as UserSettings;
return { return {
filters,
accessId: impersonationId, accessId: impersonationId,
authenticatedUserSubscription: user?.subscription, authenticatedUserSubscription: user?.subscription,
isActive: true, isActive: true,

3
libs/common/src/lib/types/impersonation-context.type.ts

@ -1,4 +1,4 @@
import { UserSettings } from '@ghostfolio/common/interfaces'; import { Filter, UserSettings } from '@ghostfolio/common/interfaces';
import { UserWithSettings } from '@ghostfolio/common/types'; import { UserWithSettings } from '@ghostfolio/common/types';
/** /**
@ -10,6 +10,7 @@ import { UserWithSettings } from '@ghostfolio/common/types';
export interface ImpersonationContext { export interface ImpersonationContext {
accessId?: string; accessId?: string;
authenticatedUserSubscription?: UserWithSettings['subscription']; authenticatedUserSubscription?: UserWithSettings['subscription'];
filters?: Filter[];
isActive: boolean; isActive: boolean;
scopes: string[]; scopes: string[];
userId: string; userId: string;

Loading…
Cancel
Save