cast-code 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/common/services/config.service.js +0 -3
- package/dist/common/services/config.service.js.map +1 -1
- package/dist/main.js +3 -1
- package/dist/main.js.map +1 -1
- package/dist/modules/mcp/catalog/mcp-templates.js +13 -2
- package/dist/modules/mcp/catalog/mcp-templates.js.map +1 -1
- package/dist/modules/mcp/services/cast-oauth-provider.js +187 -0
- package/dist/modules/mcp/services/cast-oauth-provider.js.map +1 -0
- package/dist/modules/mcp/services/mcp-client.service.js +75 -43
- package/dist/modules/mcp/services/mcp-client.service.js.map +1 -1
- package/dist/modules/mcp/services/mcp-registry.service.js +6 -0
- package/dist/modules/mcp/services/mcp-registry.service.js.map +1 -1
- package/dist/modules/repl/services/commands/mcp-commands.service.js +186 -51
- package/dist/modules/repl/services/commands/mcp-commands.service.js.map +1 -1
- package/package.json +2 -1
|
@@ -75,9 +75,6 @@ let ConfigService = class ConfigService {
|
|
|
75
75
|
ollamaBaseUrl: frontmatter.ollamaBaseUrl || process.env.OLLAMA_BASE_URL || this.config.ollamaBaseUrl
|
|
76
76
|
};
|
|
77
77
|
}
|
|
78
|
-
if (this.config.provider === 'openai' && !this.config.apiKey) {
|
|
79
|
-
throw new Error('OPENAI_API_KEY not configured. Set it in environment or ~/.cast/config.md');
|
|
80
|
-
}
|
|
81
78
|
}
|
|
82
79
|
getConfig() {
|
|
83
80
|
return this.config;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/common/services/config.service.ts"],"sourcesContent":["import { Injectable } from '@nestjs/common';\nimport * as path from 'path';\nimport { MarkdownParserService } from './markdown-parser.service';\nimport { GLOBAL_CONFIG_DIR, DEFAULT_MODEL, DEFAULT_TEMPERATURE } from '../constants';\n\ninterface GlobalConfigFrontmatter {\n model?: string;\n temperature?: number;\n apiKey?: string;\n provider?: string;\n ollamaBaseUrl?: string;\n}\n\nexport interface GlobalConfig {\n model: string;\n temperature: number;\n apiKey: string;\n provider: string;\n ollamaBaseUrl: string;\n}\n\n@Injectable()\nexport class ConfigService {\n private config: GlobalConfig = {\n model: process.env.OLLAMA_MODEL || DEFAULT_MODEL,\n temperature: DEFAULT_TEMPERATURE,\n apiKey: process.env.OPENAI_API_KEY || '',\n provider: process.env.LLM_PROVIDER || 'openai',\n ollamaBaseUrl: process.env.OLLAMA_BASE_URL || 'http://localhost:11434',\n };\n\n constructor(private readonly markdownParser: MarkdownParserService) {}\n\n async loadGlobalConfig() {\n const configPath = path.join(GLOBAL_CONFIG_DIR, 'config.md');\n\n if (await this.markdownParser.exists(configPath)) {\n const { frontmatter } =\n await this.markdownParser.parse<GlobalConfigFrontmatter>(configPath);\n\n this.config = {\n model: frontmatter.model || process.env.OLLAMA_MODEL || this.config.model,\n temperature: frontmatter.temperature ?? this.config.temperature,\n apiKey: frontmatter.apiKey || process.env.OPENAI_API_KEY || '',\n provider: frontmatter.provider || process.env.LLM_PROVIDER || this.config.provider,\n ollamaBaseUrl: frontmatter.ollamaBaseUrl || process.env.OLLAMA_BASE_URL || this.config.ollamaBaseUrl,\n };\n }\n\n
|
|
1
|
+
{"version":3,"sources":["../../../src/common/services/config.service.ts"],"sourcesContent":["import { Injectable } from '@nestjs/common';\nimport * as path from 'path';\nimport { MarkdownParserService } from './markdown-parser.service';\nimport { GLOBAL_CONFIG_DIR, DEFAULT_MODEL, DEFAULT_TEMPERATURE } from '../constants';\n\ninterface GlobalConfigFrontmatter {\n model?: string;\n temperature?: number;\n apiKey?: string;\n provider?: string;\n ollamaBaseUrl?: string;\n}\n\nexport interface GlobalConfig {\n model: string;\n temperature: number;\n apiKey: string;\n provider: string;\n ollamaBaseUrl: string;\n}\n\n@Injectable()\nexport class ConfigService {\n private config: GlobalConfig = {\n model: process.env.OLLAMA_MODEL || DEFAULT_MODEL,\n temperature: DEFAULT_TEMPERATURE,\n apiKey: process.env.OPENAI_API_KEY || '',\n provider: process.env.LLM_PROVIDER || 'openai',\n ollamaBaseUrl: process.env.OLLAMA_BASE_URL || 'http://localhost:11434',\n };\n\n constructor(private readonly markdownParser: MarkdownParserService) {}\n\n async loadGlobalConfig() {\n const configPath = path.join(GLOBAL_CONFIG_DIR, 'config.md');\n\n if (await this.markdownParser.exists(configPath)) {\n const { frontmatter } =\n await this.markdownParser.parse<GlobalConfigFrontmatter>(configPath);\n\n this.config = {\n model: frontmatter.model || process.env.OLLAMA_MODEL || this.config.model,\n temperature: frontmatter.temperature ?? this.config.temperature,\n apiKey: frontmatter.apiKey || process.env.OPENAI_API_KEY || '',\n provider: frontmatter.provider || process.env.LLM_PROVIDER || this.config.provider,\n ollamaBaseUrl: frontmatter.ollamaBaseUrl || process.env.OLLAMA_BASE_URL || this.config.ollamaBaseUrl,\n };\n }\n\n }\n\n getConfig(): GlobalConfig {\n return this.config;\n }\n\n getModel(): string {\n return this.config.model;\n }\n\n getTemperature(): number {\n return this.config.temperature;\n }\n\n getApiKey(): string {\n return this.config.apiKey;\n }\n\n getProvider(): string {\n return this.config.provider;\n }\n\n getOllamaBaseUrl(): string {\n return this.config.ollamaBaseUrl;\n }\n}\n"],"names":["ConfigService","loadGlobalConfig","configPath","path","join","GLOBAL_CONFIG_DIR","markdownParser","exists","frontmatter","parse","config","model","process","env","OLLAMA_MODEL","temperature","apiKey","OPENAI_API_KEY","provider","LLM_PROVIDER","ollamaBaseUrl","OLLAMA_BASE_URL","getConfig","getModel","getTemperature","getApiKey","getProvider","getOllamaBaseUrl","DEFAULT_MODEL","DEFAULT_TEMPERATURE"],"mappings":";;;;+BAsBaA;;;eAAAA;;;wBAtBc;8DACL;uCACgB;2BACgC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmB/D,IAAA,AAAMA,gBAAN,MAAMA;IAWX,MAAMC,mBAAmB;QACvB,MAAMC,aAAaC,MAAKC,IAAI,CAACC,4BAAiB,EAAE;QAEhD,IAAI,MAAM,IAAI,CAACC,cAAc,CAACC,MAAM,CAACL,aAAa;YAChD,MAAM,EAAEM,WAAW,EAAE,GACnB,MAAM,IAAI,CAACF,cAAc,CAACG,KAAK,CAA0BP;YAE3D,IAAI,CAACQ,MAAM,GAAG;gBACZC,OAAOH,YAAYG,KAAK,IAAIC,QAAQC,GAAG,CAACC,YAAY,IAAI,IAAI,CAACJ,MAAM,CAACC,KAAK;gBACzEI,aAAaP,YAAYO,WAAW,IAAI,IAAI,CAACL,MAAM,CAACK,WAAW;gBAC/DC,QAAQR,YAAYQ,MAAM,IAAIJ,QAAQC,GAAG,CAACI,cAAc,IAAI;gBAC5DC,UAAUV,YAAYU,QAAQ,IAAIN,QAAQC,GAAG,CAACM,YAAY,IAAI,IAAI,CAACT,MAAM,CAACQ,QAAQ;gBAClFE,eAAeZ,YAAYY,aAAa,IAAIR,QAAQC,GAAG,CAACQ,eAAe,IAAI,IAAI,CAACX,MAAM,CAACU,aAAa;YACtG;QACF;IAEF;IAEAE,YAA0B;QACxB,OAAO,IAAI,CAACZ,MAAM;IACpB;IAEAa,WAAmB;QACjB,OAAO,IAAI,CAACb,MAAM,CAACC,KAAK;IAC1B;IAEAa,iBAAyB;QACvB,OAAO,IAAI,CAACd,MAAM,CAACK,WAAW;IAChC;IAEAU,YAAoB;QAClB,OAAO,IAAI,CAACf,MAAM,CAACM,MAAM;IAC3B;IAEAU,cAAsB;QACpB,OAAO,IAAI,CAAChB,MAAM,CAACQ,QAAQ;IAC7B;IAEAS,mBAA2B;QACzB,OAAO,IAAI,CAACjB,MAAM,CAACU,aAAa;IAClC;IA1CA,YAAY,AAAiBd,cAAqC,CAAE;aAAvCA,iBAAAA;aARrBI,SAAuB;YAC7BC,OAAOC,QAAQC,GAAG,CAACC,YAAY,IAAIc,wBAAa;YAChDb,aAAac,8BAAmB;YAChCb,QAAQJ,QAAQC,GAAG,CAACI,cAAc,IAAI;YACtCC,UAAUN,QAAQC,GAAG,CAACM,YAAY,IAAI;YACtCC,eAAeR,QAAQC,GAAG,CAACQ,eAAe,IAAI;QAChD;IAEqE;AA2CvE"}
|
package/dist/main.js
CHANGED
|
@@ -10,7 +10,9 @@ const _appmodule = require("./app.module");
|
|
|
10
10
|
const _replservice = require("./modules/repl/services/repl.service");
|
|
11
11
|
const _configmanagerservice = require("./modules/config/services/config-manager.service");
|
|
12
12
|
const _initconfigservice = require("./modules/config/services/init-config.service");
|
|
13
|
-
(0, _dotenv.config)(
|
|
13
|
+
(0, _dotenv.config)({
|
|
14
|
+
quiet: true
|
|
15
|
+
});
|
|
14
16
|
async function checkAndRunSetup(configManager, initService) {
|
|
15
17
|
const hasConfig = await configManager.configExists();
|
|
16
18
|
if (!hasConfig) {
|
package/dist/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/main.ts"],"sourcesContent":["#!/usr/bin/env node\nimport 'reflect-metadata';\nimport { config } from 'dotenv';\nimport { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ReplService } from './modules/repl/services/repl.service';\nimport { ConfigManagerService } from './modules/config/services/config-manager.service';\nimport { InitConfigService } from './modules/config/services/init-config.service';\n\nconfig();\n\nasync function checkAndRunSetup(configManager: ConfigManagerService, initService: InitConfigService): Promise<boolean> {\n const hasConfig = await configManager.configExists();\n \n if (!hasConfig) {\n console.log('\\n👋 Bem-vindo ao Cast Code!\\n');\n console.log('Parece que esta é a primeira vez que você executa o Cast.');\n console.log('Vamos fazer a configuração inicial agora.\\n');\n\n try {\n await initService.runInitialSetup();\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n console.error(`\\n❌ Falha na configuração inicial: ${message}\\n`);\n return false;\n }\n\n const created = await configManager.configExists();\n if (!created) {\n console.log('\\n⚠️ Configuração não concluída. Rode: cast config init\\n');\n return false;\n }\n\n return true;\n }\n \n return true;\n}\n\nasync function bootstrap() {\n const args = process.argv.slice(2);\n const command = args[0];\n \n if (command === 'config' || command === 'init') {\n const app = await NestFactory.createApplicationContext(AppModule, {\n logger: false,\n });\n \n const configCommands = app.get(InitConfigService);\n try {\n await configCommands.runInitialSetup();\n } catch (error) {\n const message = error instanceof Error ? error.stack || error.message : String(error);\n console.error('\\nFailed to run initial setup:\\n', message);\n process.exitCode = 1;\n }\n await app.close();\n return;\n }\n\n const app = await NestFactory.createApplicationContext(AppModule, {\n logger: false,\n });\n\n const configManager = app.get(ConfigManagerService);\n const initService = app.get(InitConfigService);\n \n const ready = await checkAndRunSetup(configManager, initService);\n \n if (!ready) {\n await app.close();\n process.exit(1);\n }\n\n await configManager.loadConfig();\n\n const repl = app.get(ReplService);\n\n process.on('SIGINT', () => {\n repl.stop();\n app.close();\n process.exit(0);\n });\n\n try {\n await repl.start();\n } catch (error) {\n console.error('Failed to start:', (error as Error).message);\n process.exit(1);\n }\n}\n\nbootstrap().catch((error) => {\n const message = error instanceof Error ? error.stack || error.message : String(error);\n console.error('\\nFatal bootstrap error:\\n', message);\n process.exit(1);\n});\n"],"names":["config","checkAndRunSetup","configManager","initService","hasConfig","configExists","console","log","runInitialSetup","error","message","Error","String","created","bootstrap","args","process","argv","slice","command","app","NestFactory","createApplicationContext","AppModule","logger","configCommands","get","InitConfigService","stack","exitCode","close","ConfigManagerService","ready","exit","loadConfig","repl","ReplService","on","stop","start","catch"],"mappings":";;;;;QACO;wBACgB;sBACK;2BACF;6BACE;sCACS;mCACH;AAElCA,IAAAA,cAAM;
|
|
1
|
+
{"version":3,"sources":["../src/main.ts"],"sourcesContent":["#!/usr/bin/env node\nimport 'reflect-metadata';\nimport { config } from 'dotenv';\nimport { NestFactory } from '@nestjs/core';\nimport { AppModule } from './app.module';\nimport { ReplService } from './modules/repl/services/repl.service';\nimport { ConfigManagerService } from './modules/config/services/config-manager.service';\nimport { InitConfigService } from './modules/config/services/init-config.service';\n\nconfig({ quiet: true });\n\nasync function checkAndRunSetup(configManager: ConfigManagerService, initService: InitConfigService): Promise<boolean> {\n const hasConfig = await configManager.configExists();\n \n if (!hasConfig) {\n console.log('\\n👋 Bem-vindo ao Cast Code!\\n');\n console.log('Parece que esta é a primeira vez que você executa o Cast.');\n console.log('Vamos fazer a configuração inicial agora.\\n');\n\n try {\n await initService.runInitialSetup();\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n console.error(`\\n❌ Falha na configuração inicial: ${message}\\n`);\n return false;\n }\n\n const created = await configManager.configExists();\n if (!created) {\n console.log('\\n⚠️ Configuração não concluída. Rode: cast config init\\n');\n return false;\n }\n\n return true;\n }\n \n return true;\n}\n\nasync function bootstrap() {\n const args = process.argv.slice(2);\n const command = args[0];\n \n if (command === 'config' || command === 'init') {\n const app = await NestFactory.createApplicationContext(AppModule, {\n logger: false,\n });\n \n const configCommands = app.get(InitConfigService);\n try {\n await configCommands.runInitialSetup();\n } catch (error) {\n const message = error instanceof Error ? error.stack || error.message : String(error);\n console.error('\\nFailed to run initial setup:\\n', message);\n process.exitCode = 1;\n }\n await app.close();\n return;\n }\n\n const app = await NestFactory.createApplicationContext(AppModule, {\n logger: false,\n });\n\n const configManager = app.get(ConfigManagerService);\n const initService = app.get(InitConfigService);\n \n const ready = await checkAndRunSetup(configManager, initService);\n \n if (!ready) {\n await app.close();\n process.exit(1);\n }\n\n await configManager.loadConfig();\n\n const repl = app.get(ReplService);\n\n process.on('SIGINT', () => {\n repl.stop();\n app.close();\n process.exit(0);\n });\n\n try {\n await repl.start();\n } catch (error) {\n console.error('Failed to start:', (error as Error).message);\n process.exit(1);\n }\n}\n\nbootstrap().catch((error) => {\n const message = error instanceof Error ? error.stack || error.message : String(error);\n console.error('\\nFatal bootstrap error:\\n', message);\n process.exit(1);\n});\n"],"names":["config","quiet","checkAndRunSetup","configManager","initService","hasConfig","configExists","console","log","runInitialSetup","error","message","Error","String","created","bootstrap","args","process","argv","slice","command","app","NestFactory","createApplicationContext","AppModule","logger","configCommands","get","InitConfigService","stack","exitCode","close","ConfigManagerService","ready","exit","loadConfig","repl","ReplService","on","stop","start","catch"],"mappings":";;;;;QACO;wBACgB;sBACK;2BACF;6BACE;sCACS;mCACH;AAElCA,IAAAA,cAAM,EAAC;IAAEC,OAAO;AAAK;AAErB,eAAeC,iBAAiBC,aAAmC,EAAEC,WAA8B;IACjG,MAAMC,YAAY,MAAMF,cAAcG,YAAY;IAElD,IAAI,CAACD,WAAW;QACdE,QAAQC,GAAG,CAAC;QACZD,QAAQC,GAAG,CAAC;QACZD,QAAQC,GAAG,CAAC;QAEZ,IAAI;YACF,MAAMJ,YAAYK,eAAe;QACnC,EAAE,OAAOC,OAAO;YACd,MAAMC,UAAUD,iBAAiBE,QAAQF,MAAMC,OAAO,GAAGE,OAAOH;YAChEH,QAAQG,KAAK,CAAC,CAAC,mCAAmC,EAAEC,QAAQ,EAAE,CAAC;YAC/D,OAAO;QACT;QAEA,MAAMG,UAAU,MAAMX,cAAcG,YAAY;QAChD,IAAI,CAACQ,SAAS;YACZP,QAAQC,GAAG,CAAC;YACZ,OAAO;QACT;QAEA,OAAO;IACT;IAEA,OAAO;AACT;AAEA,eAAeO;IACb,MAAMC,OAAOC,QAAQC,IAAI,CAACC,KAAK,CAAC;IAChC,MAAMC,UAAUJ,IAAI,CAAC,EAAE;IAEvB,IAAII,YAAY,YAAYA,YAAY,QAAQ;QAC9C,MAAMC,MAAM,MAAMC,iBAAW,CAACC,wBAAwB,CAACC,oBAAS,EAAE;YAChEC,QAAQ;QACV;QAEA,MAAMC,iBAAiBL,IAAIM,GAAG,CAACC,oCAAiB;QAChD,IAAI;YACF,MAAMF,eAAejB,eAAe;QACtC,EAAE,OAAOC,OAAO;YACd,MAAMC,UAAUD,iBAAiBE,QAAQF,MAAMmB,KAAK,IAAInB,MAAMC,OAAO,GAAGE,OAAOH;YAC/EH,QAAQG,KAAK,CAAC,oCAAoCC;YAClDM,QAAQa,QAAQ,GAAG;QACrB;QACA,MAAMT,IAAIU,KAAK;QACf;IACF;IAEA,MAAMV,MAAM,MAAMC,iBAAW,CAACC,wBAAwB,CAACC,oBAAS,EAAE;QAChEC,QAAQ;IACV;IAEA,MAAMtB,gBAAgBkB,IAAIM,GAAG,CAACK,0CAAoB;IAClD,MAAM5B,cAAciB,IAAIM,GAAG,CAACC,oCAAiB;IAE7C,MAAMK,QAAQ,MAAM/B,iBAAiBC,eAAeC;IAEpD,IAAI,CAAC6B,OAAO;QACV,MAAMZ,IAAIU,KAAK;QACfd,QAAQiB,IAAI,CAAC;IACf;IAEA,MAAM/B,cAAcgC,UAAU;IAE9B,MAAMC,OAAOf,IAAIM,GAAG,CAACU,wBAAW;IAEhCpB,QAAQqB,EAAE,CAAC,UAAU;QACnBF,KAAKG,IAAI;QACTlB,IAAIU,KAAK;QACTd,QAAQiB,IAAI,CAAC;IACf;IAEA,IAAI;QACF,MAAME,KAAKI,KAAK;IAClB,EAAE,OAAO9B,OAAO;QACdH,QAAQG,KAAK,CAAC,oBAAoB,AAACA,MAAgBC,OAAO;QAC1DM,QAAQiB,IAAI,CAAC;IACf;AACF;AAEAnB,YAAY0B,KAAK,CAAC,CAAC/B;IACjB,MAAMC,UAAUD,iBAAiBE,QAAQF,MAAMmB,KAAK,IAAInB,MAAMC,OAAO,GAAGE,OAAOH;IAC/EH,QAAQG,KAAK,CAAC,8BAA8BC;IAC5CM,QAAQiB,IAAI,CAAC;AACf"}
|
|
@@ -149,8 +149,19 @@ const MCP_TEMPLATES = {
|
|
|
149
149
|
// ===== DESIGN =====
|
|
150
150
|
figma: {
|
|
151
151
|
id: 'figma',
|
|
152
|
-
name: 'Figma',
|
|
153
|
-
description: 'Acesse designs
|
|
152
|
+
name: 'Figma Desktop',
|
|
153
|
+
description: 'Acesse designs via app desktop local (sem OAuth)',
|
|
154
|
+
category: 'design',
|
|
155
|
+
config: {
|
|
156
|
+
type: 'http',
|
|
157
|
+
endpoint: 'http://127.0.0.1:3845/mcp'
|
|
158
|
+
},
|
|
159
|
+
credentials: []
|
|
160
|
+
},
|
|
161
|
+
'figma-remote': {
|
|
162
|
+
id: 'figma-remote',
|
|
163
|
+
name: 'Figma Remote (OAuth)',
|
|
164
|
+
description: 'Servidor remoto Figma — requer cliente pré-aprovado',
|
|
154
165
|
category: 'design',
|
|
155
166
|
config: {
|
|
156
167
|
type: 'http',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/modules/mcp/catalog/mcp-templates.ts"],"sourcesContent":["import { McpConfig } from '../types';\n\nexport type McpCategory = 'dev' | 'design' | 'data' | 'search' | 'cloud' | 'productivity' | 'payments' | 'browser' | 'filesystem';\n\nexport interface McpTemplate {\n id: string;\n name: string;\n description: string;\n category: McpCategory;\n config: McpConfig;\n credentials: {\n name: string;\n envVar: string;\n placeholder: string;\n required: boolean;\n isArg?: boolean;\n }[];\n}\n\nexport const MCP_TEMPLATES: Record<string, McpTemplate> = {\n // ===== DEV TOOLS =====\n github: {\n id: 'github',\n name: 'GitHub',\n description: 'Acesse repos, issues, PRs',\n category: 'dev',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@modelcontextprotocol/server-github'],\n env: {},\n },\n credentials: [\n {\n name: 'GitHub Token',\n envVar: 'GITHUB_PERSONAL_ACCESS_TOKEN',\n placeholder: 'ghp_...',\n required: true,\n },\n ],\n },\n\n linear: {\n id: 'linear',\n name: 'Linear',\n description: 'Gerencie issues e projetos',\n category: 'dev',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@larryhudson/linear-mcp-server'],\n env: {},\n },\n credentials: [\n {\n name: 'Linear API Key',\n envVar: 'LINEAR_API_KEY',\n placeholder: 'lin_api_...',\n required: true,\n },\n ],\n },\n\n jira: {\n id: 'jira',\n name: 'Jira',\n description: 'Gerencie issues e sprints',\n category: 'dev',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@aashari/mcp-server-atlassian-jira'],\n env: {},\n },\n credentials: [\n {\n name: 'Jira Host',\n envVar: 'JIRA_HOST',\n placeholder: 'empresa.atlassian.net',\n required: true,\n },\n {\n name: 'Jira Email',\n envVar: 'JIRA_EMAIL',\n placeholder: 'você@empresa.com',\n required: true,\n },\n {\n name: 'Jira API Token',\n envVar: 'JIRA_API_TOKEN',\n placeholder: 'ATATT...',\n required: true,\n },\n ],\n },\n\n sentry: {\n id: 'sentry',\n name: 'Sentry',\n description: 'Monitore erros e performance',\n category: 'dev',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@sentry/mcp-server'],\n env: {\n EMBEDDED_AGENT_PROVIDER: 'anthropic',\n },\n },\n credentials: [\n {\n name: 'Sentry Access Token',\n envVar: 'SENTRY_ACCESS_TOKEN',\n placeholder: 'sntrys_...',\n required: true,\n },\n ],\n },\n\n docker: {\n id: 'docker',\n name: 'Docker',\n description: 'Gerencie containers e images',\n category: 'dev',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@0xshariq/docker-mcp-server'],\n env: {},\n },\n credentials: [],\n },\n\n // ===== DESIGN =====\n figma: {\n id: 'figma',\n name: 'Figma',\n description: 'Acesse designs e componentes (OAuth)',\n category: 'design',\n config: {\n type: 'http',\n endpoint: 'https://mcp.figma.com/mcp',\n },\n credentials: [],\n },\n\n // ===== DATA =====\n postgres: {\n id: 'postgres',\n name: 'PostgreSQL',\n description: 'Consulte bancos de dados',\n category: 'data',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@modelcontextprotocol/server-postgres'],\n env: {},\n },\n credentials: [\n {\n name: 'Database URL',\n envVar: '',\n placeholder: 'postgresql://user:pass@host/db',\n required: true,\n isArg: true,\n },\n ],\n },\n\n mongodb: {\n id: 'mongodb',\n name: 'MongoDB',\n description: 'Consulte coleções e documentos',\n category: 'data',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@mongodb-js/mongodb-mcp-server'],\n env: {},\n },\n credentials: [\n {\n name: 'Connection String',\n envVar: 'MDB_MCP_CONNECTION_STRING',\n placeholder: 'mongodb+srv://...',\n required: true,\n },\n ],\n },\n\n redis: {\n id: 'redis',\n name: 'Redis',\n description: 'Cache e key-value store',\n category: 'data',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@modelcontextprotocol/server-redis'],\n env: {},\n },\n credentials: [\n {\n name: 'Redis URL',\n envVar: 'REDIS_URL',\n placeholder: 'redis://localhost:6379',\n required: true,\n },\n ],\n },\n\n supabase: {\n id: 'supabase',\n name: 'Supabase',\n description: 'Banco de dados e backend',\n category: 'data',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@cloud9-labs/mcp-supabase'],\n env: {},\n },\n credentials: [\n {\n name: 'Supabase URL',\n envVar: 'SUPABASE_URL',\n placeholder: 'https://xyz.supabase.co',\n required: true,\n },\n {\n name: 'Service Key',\n envVar: 'SUPABASE_SERVICE_KEY',\n placeholder: 'eyJ...',\n required: true,\n },\n ],\n },\n\n // ===== SEARCH =====\n 'brave-search': {\n id: 'brave-search',\n name: 'Brave Search',\n description: 'Busca na web',\n category: 'search',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@modelcontextprotocol/server-brave-search'],\n env: {},\n },\n credentials: [\n {\n name: 'Brave API Key',\n envVar: 'BRAVE_API_KEY',\n placeholder: 'BSA...',\n required: true,\n },\n ],\n },\n\n exa: {\n id: 'exa',\n name: 'Exa Search',\n description: 'Busca semântica na web',\n category: 'search',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', 'exa-mcp-server'],\n env: {},\n },\n credentials: [\n {\n name: 'Exa API Key',\n envVar: 'EXA_API_KEY',\n placeholder: 'exa_...',\n required: true,\n },\n ],\n },\n\n perplexity: {\n id: 'perplexity',\n name: 'Perplexity',\n description: 'Busca com IA',\n category: 'search',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@perplexity-ai/mcp-server'],\n env: {},\n },\n credentials: [\n {\n name: 'Perplexity API Key',\n envVar: 'PERPLEXITY_API_KEY',\n placeholder: 'pplx-...',\n required: true,\n },\n ],\n },\n\n context7: {\n id: 'context7',\n name: 'Context7',\n description: 'Busca em documentações técnicas',\n category: 'search',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@upstash/context7-mcp'],\n env: {},\n },\n credentials: [],\n },\n\n // ===== CLOUD =====\n vercel: {\n id: 'vercel',\n name: 'Vercel',\n description: 'Deploy e gerenciamento',\n category: 'cloud',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@vercel/mcp-adapter'],\n env: {},\n },\n credentials: [],\n },\n\n cloudflare: {\n id: 'cloudflare',\n name: 'Cloudflare',\n description: 'Workers, KV, R2',\n category: 'cloud',\n config: {\n type: 'http',\n endpoint: 'https://mcp.cloudflare.com',\n },\n credentials: [],\n },\n\n 'aws-s3': {\n id: 'aws-s3',\n name: 'AWS S3',\n description: 'Armazenamento de objetos',\n category: 'cloud',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', 'aws-s3-mcp'],\n env: {},\n },\n credentials: [\n {\n name: 'Access Key ID',\n envVar: 'AWS_ACCESS_KEY_ID',\n placeholder: 'AKIA...',\n required: true,\n },\n {\n name: 'Secret Access Key',\n envVar: 'AWS_SECRET_ACCESS_KEY',\n placeholder: 'xxx',\n required: true,\n },\n {\n name: 'Region',\n envVar: 'AWS_REGION',\n placeholder: 'us-east-1',\n required: true,\n },\n ],\n },\n\n // ===== PRODUCTIVITY =====\n slack: {\n id: 'slack',\n name: 'Slack',\n description: 'Envie mensagens e gerencie canais',\n category: 'productivity',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', 'slack-mcp-server@latest', '--transport', 'stdio'],\n env: {},\n },\n credentials: [\n {\n name: 'Slack Bot Token',\n envVar: 'SLACK_BOT_TOKEN',\n placeholder: 'xoxb-...',\n required: true,\n },\n {\n name: 'Team ID',\n envVar: 'SLACK_TEAM_ID',\n placeholder: 'T...',\n required: true,\n },\n ],\n },\n\n notion: {\n id: 'notion',\n name: 'Notion',\n description: 'Gerencie páginas e databases',\n category: 'productivity',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@notionhq/notion-mcp-server'],\n env: {},\n },\n credentials: [\n {\n name: 'Notion Token',\n envVar: 'NOTION_TOKEN',\n placeholder: 'secret_...',\n required: true,\n },\n ],\n },\n\n 'google-drive': {\n id: 'google-drive',\n name: 'Google Drive',\n description: 'Acesse arquivos e pastas (OAuth)',\n category: 'productivity',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@modelcontextprotocol/server-gdrive'],\n env: {},\n },\n credentials: [],\n },\n\n 'google-maps': {\n id: 'google-maps',\n name: 'Google Maps',\n description: 'Geocoding e rotas',\n category: 'productivity',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@googlemaps/code-assist-mcp@latest'],\n env: {},\n },\n credentials: [],\n },\n\n // ===== PAYMENTS =====\n stripe: {\n id: 'stripe',\n name: 'Stripe',\n description: 'Pagamentos e assinaturas',\n category: 'payments',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@stripe/mcp', '--tools=all'],\n env: {},\n },\n credentials: [\n {\n name: 'Stripe Secret Key',\n envVar: 'STRIPE_SECRET_KEY',\n placeholder: 'sk_test_... ou rk_...',\n required: true,\n },\n ],\n },\n\n twilio: {\n id: 'twilio',\n name: 'Twilio',\n description: 'SMS e chamadas',\n category: 'payments',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@twilio-alpha/mcp'],\n env: {},\n },\n credentials: [\n {\n name: 'Account SID',\n envVar: '',\n placeholder: 'AC...',\n required: true,\n isArg: true,\n },\n {\n name: 'API Key:Secret',\n envVar: '',\n placeholder: 'SK...:...',\n required: true,\n isArg: true,\n },\n ],\n },\n\n // ===== BROWSER =====\n puppeteer: {\n id: 'puppeteer',\n name: 'Puppeteer',\n description: 'Automação de browser',\n category: 'browser',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@modelcontextprotocol/server-puppeteer'],\n env: {},\n },\n credentials: [],\n },\n\n // ===== FILESYSTEM =====\n filesystem: {\n id: 'filesystem',\n name: 'Filesystem',\n description: 'Acesse arquivos locais',\n category: 'filesystem',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@modelcontextprotocol/server-filesystem'],\n env: {},\n },\n credentials: [\n {\n name: 'Diretório permitido',\n envVar: '',\n placeholder: '/caminho/para/diretório',\n required: true,\n isArg: true,\n },\n ],\n },\n};\n\nexport function getTemplatesByCategory(category: McpCategory): McpTemplate[] {\n return Object.values(MCP_TEMPLATES).filter(t => t.category === category);\n}\n\nexport function getAllTemplates(): McpTemplate[] {\n return Object.values(MCP_TEMPLATES);\n}\n\nexport function getTemplate(id: string): McpTemplate | undefined {\n return MCP_TEMPLATES[id];\n}\n"],"names":["MCP_TEMPLATES","getAllTemplates","getTemplate","getTemplatesByCategory","github","id","name","description","category","config","type","command","args","env","credentials","envVar","placeholder","required","linear","jira","sentry","EMBEDDED_AGENT_PROVIDER","docker","figma","endpoint","postgres","isArg","mongodb","redis","supabase","exa","perplexity","context7","vercel","cloudflare","slack","notion","stripe","twilio","puppeteer","filesystem","Object","values","filter","t"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/modules/mcp/catalog/mcp-templates.ts"],"sourcesContent":["import { McpConfig } from '../types';\n\nexport type McpCategory = 'dev' | 'design' | 'data' | 'search' | 'cloud' | 'productivity' | 'payments' | 'browser' | 'filesystem';\n\nexport interface McpTemplate {\n id: string;\n name: string;\n description: string;\n category: McpCategory;\n config: McpConfig;\n credentials: {\n name: string;\n envVar: string;\n placeholder: string;\n required: boolean;\n isArg?: boolean;\n }[];\n}\n\nexport const MCP_TEMPLATES: Record<string, McpTemplate> = {\n // ===== DEV TOOLS =====\n github: {\n id: 'github',\n name: 'GitHub',\n description: 'Acesse repos, issues, PRs',\n category: 'dev',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@modelcontextprotocol/server-github'],\n env: {},\n },\n credentials: [\n {\n name: 'GitHub Token',\n envVar: 'GITHUB_PERSONAL_ACCESS_TOKEN',\n placeholder: 'ghp_...',\n required: true,\n },\n ],\n },\n\n linear: {\n id: 'linear',\n name: 'Linear',\n description: 'Gerencie issues e projetos',\n category: 'dev',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@larryhudson/linear-mcp-server'],\n env: {},\n },\n credentials: [\n {\n name: 'Linear API Key',\n envVar: 'LINEAR_API_KEY',\n placeholder: 'lin_api_...',\n required: true,\n },\n ],\n },\n\n jira: {\n id: 'jira',\n name: 'Jira',\n description: 'Gerencie issues e sprints',\n category: 'dev',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@aashari/mcp-server-atlassian-jira'],\n env: {},\n },\n credentials: [\n {\n name: 'Jira Host',\n envVar: 'JIRA_HOST',\n placeholder: 'empresa.atlassian.net',\n required: true,\n },\n {\n name: 'Jira Email',\n envVar: 'JIRA_EMAIL',\n placeholder: 'você@empresa.com',\n required: true,\n },\n {\n name: 'Jira API Token',\n envVar: 'JIRA_API_TOKEN',\n placeholder: 'ATATT...',\n required: true,\n },\n ],\n },\n\n sentry: {\n id: 'sentry',\n name: 'Sentry',\n description: 'Monitore erros e performance',\n category: 'dev',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@sentry/mcp-server'],\n env: {\n EMBEDDED_AGENT_PROVIDER: 'anthropic',\n },\n },\n credentials: [\n {\n name: 'Sentry Access Token',\n envVar: 'SENTRY_ACCESS_TOKEN',\n placeholder: 'sntrys_...',\n required: true,\n },\n ],\n },\n\n docker: {\n id: 'docker',\n name: 'Docker',\n description: 'Gerencie containers e images',\n category: 'dev',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@0xshariq/docker-mcp-server'],\n env: {},\n },\n credentials: [],\n },\n\n // ===== DESIGN =====\n figma: {\n id: 'figma',\n name: 'Figma Desktop',\n description: 'Acesse designs via app desktop local (sem OAuth)',\n category: 'design',\n config: {\n type: 'http',\n endpoint: 'http://127.0.0.1:3845/mcp',\n },\n credentials: [],\n },\n\n 'figma-remote': {\n id: 'figma-remote',\n name: 'Figma Remote (OAuth)',\n description: 'Servidor remoto Figma — requer cliente pré-aprovado',\n category: 'design',\n config: {\n type: 'http',\n endpoint: 'https://mcp.figma.com/mcp',\n },\n credentials: [],\n },\n\n // ===== DATA =====\n postgres: {\n id: 'postgres',\n name: 'PostgreSQL',\n description: 'Consulte bancos de dados',\n category: 'data',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@modelcontextprotocol/server-postgres'],\n env: {},\n },\n credentials: [\n {\n name: 'Database URL',\n envVar: '',\n placeholder: 'postgresql://user:pass@host/db',\n required: true,\n isArg: true,\n },\n ],\n },\n\n mongodb: {\n id: 'mongodb',\n name: 'MongoDB',\n description: 'Consulte coleções e documentos',\n category: 'data',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@mongodb-js/mongodb-mcp-server'],\n env: {},\n },\n credentials: [\n {\n name: 'Connection String',\n envVar: 'MDB_MCP_CONNECTION_STRING',\n placeholder: 'mongodb+srv://...',\n required: true,\n },\n ],\n },\n\n redis: {\n id: 'redis',\n name: 'Redis',\n description: 'Cache e key-value store',\n category: 'data',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@modelcontextprotocol/server-redis'],\n env: {},\n },\n credentials: [\n {\n name: 'Redis URL',\n envVar: 'REDIS_URL',\n placeholder: 'redis://localhost:6379',\n required: true,\n },\n ],\n },\n\n supabase: {\n id: 'supabase',\n name: 'Supabase',\n description: 'Banco de dados e backend',\n category: 'data',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@cloud9-labs/mcp-supabase'],\n env: {},\n },\n credentials: [\n {\n name: 'Supabase URL',\n envVar: 'SUPABASE_URL',\n placeholder: 'https://xyz.supabase.co',\n required: true,\n },\n {\n name: 'Service Key',\n envVar: 'SUPABASE_SERVICE_KEY',\n placeholder: 'eyJ...',\n required: true,\n },\n ],\n },\n\n // ===== SEARCH =====\n 'brave-search': {\n id: 'brave-search',\n name: 'Brave Search',\n description: 'Busca na web',\n category: 'search',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@modelcontextprotocol/server-brave-search'],\n env: {},\n },\n credentials: [\n {\n name: 'Brave API Key',\n envVar: 'BRAVE_API_KEY',\n placeholder: 'BSA...',\n required: true,\n },\n ],\n },\n\n exa: {\n id: 'exa',\n name: 'Exa Search',\n description: 'Busca semântica na web',\n category: 'search',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', 'exa-mcp-server'],\n env: {},\n },\n credentials: [\n {\n name: 'Exa API Key',\n envVar: 'EXA_API_KEY',\n placeholder: 'exa_...',\n required: true,\n },\n ],\n },\n\n perplexity: {\n id: 'perplexity',\n name: 'Perplexity',\n description: 'Busca com IA',\n category: 'search',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@perplexity-ai/mcp-server'],\n env: {},\n },\n credentials: [\n {\n name: 'Perplexity API Key',\n envVar: 'PERPLEXITY_API_KEY',\n placeholder: 'pplx-...',\n required: true,\n },\n ],\n },\n\n context7: {\n id: 'context7',\n name: 'Context7',\n description: 'Busca em documentações técnicas',\n category: 'search',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@upstash/context7-mcp'],\n env: {},\n },\n credentials: [],\n },\n\n // ===== CLOUD =====\n vercel: {\n id: 'vercel',\n name: 'Vercel',\n description: 'Deploy e gerenciamento',\n category: 'cloud',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@vercel/mcp-adapter'],\n env: {},\n },\n credentials: [],\n },\n\n cloudflare: {\n id: 'cloudflare',\n name: 'Cloudflare',\n description: 'Workers, KV, R2',\n category: 'cloud',\n config: {\n type: 'http',\n endpoint: 'https://mcp.cloudflare.com',\n },\n credentials: [],\n },\n\n 'aws-s3': {\n id: 'aws-s3',\n name: 'AWS S3',\n description: 'Armazenamento de objetos',\n category: 'cloud',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', 'aws-s3-mcp'],\n env: {},\n },\n credentials: [\n {\n name: 'Access Key ID',\n envVar: 'AWS_ACCESS_KEY_ID',\n placeholder: 'AKIA...',\n required: true,\n },\n {\n name: 'Secret Access Key',\n envVar: 'AWS_SECRET_ACCESS_KEY',\n placeholder: 'xxx',\n required: true,\n },\n {\n name: 'Region',\n envVar: 'AWS_REGION',\n placeholder: 'us-east-1',\n required: true,\n },\n ],\n },\n\n // ===== PRODUCTIVITY =====\n slack: {\n id: 'slack',\n name: 'Slack',\n description: 'Envie mensagens e gerencie canais',\n category: 'productivity',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', 'slack-mcp-server@latest', '--transport', 'stdio'],\n env: {},\n },\n credentials: [\n {\n name: 'Slack Bot Token',\n envVar: 'SLACK_BOT_TOKEN',\n placeholder: 'xoxb-...',\n required: true,\n },\n {\n name: 'Team ID',\n envVar: 'SLACK_TEAM_ID',\n placeholder: 'T...',\n required: true,\n },\n ],\n },\n\n notion: {\n id: 'notion',\n name: 'Notion',\n description: 'Gerencie páginas e databases',\n category: 'productivity',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@notionhq/notion-mcp-server'],\n env: {},\n },\n credentials: [\n {\n name: 'Notion Token',\n envVar: 'NOTION_TOKEN',\n placeholder: 'secret_...',\n required: true,\n },\n ],\n },\n\n 'google-drive': {\n id: 'google-drive',\n name: 'Google Drive',\n description: 'Acesse arquivos e pastas (OAuth)',\n category: 'productivity',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@modelcontextprotocol/server-gdrive'],\n env: {},\n },\n credentials: [],\n },\n\n 'google-maps': {\n id: 'google-maps',\n name: 'Google Maps',\n description: 'Geocoding e rotas',\n category: 'productivity',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@googlemaps/code-assist-mcp@latest'],\n env: {},\n },\n credentials: [],\n },\n\n // ===== PAYMENTS =====\n stripe: {\n id: 'stripe',\n name: 'Stripe',\n description: 'Pagamentos e assinaturas',\n category: 'payments',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@stripe/mcp', '--tools=all'],\n env: {},\n },\n credentials: [\n {\n name: 'Stripe Secret Key',\n envVar: 'STRIPE_SECRET_KEY',\n placeholder: 'sk_test_... ou rk_...',\n required: true,\n },\n ],\n },\n\n twilio: {\n id: 'twilio',\n name: 'Twilio',\n description: 'SMS e chamadas',\n category: 'payments',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@twilio-alpha/mcp'],\n env: {},\n },\n credentials: [\n {\n name: 'Account SID',\n envVar: '',\n placeholder: 'AC...',\n required: true,\n isArg: true,\n },\n {\n name: 'API Key:Secret',\n envVar: '',\n placeholder: 'SK...:...',\n required: true,\n isArg: true,\n },\n ],\n },\n\n // ===== BROWSER =====\n puppeteer: {\n id: 'puppeteer',\n name: 'Puppeteer',\n description: 'Automação de browser',\n category: 'browser',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@modelcontextprotocol/server-puppeteer'],\n env: {},\n },\n credentials: [],\n },\n\n // ===== FILESYSTEM =====\n filesystem: {\n id: 'filesystem',\n name: 'Filesystem',\n description: 'Acesse arquivos locais',\n category: 'filesystem',\n config: {\n type: 'stdio',\n command: 'npx',\n args: ['-y', '@modelcontextprotocol/server-filesystem'],\n env: {},\n },\n credentials: [\n {\n name: 'Diretório permitido',\n envVar: '',\n placeholder: '/caminho/para/diretório',\n required: true,\n isArg: true,\n },\n ],\n },\n};\n\nexport function getTemplatesByCategory(category: McpCategory): McpTemplate[] {\n return Object.values(MCP_TEMPLATES).filter(t => t.category === category);\n}\n\nexport function getAllTemplates(): McpTemplate[] {\n return Object.values(MCP_TEMPLATES);\n}\n\nexport function getTemplate(id: string): McpTemplate | undefined {\n return MCP_TEMPLATES[id];\n}\n"],"names":["MCP_TEMPLATES","getAllTemplates","getTemplate","getTemplatesByCategory","github","id","name","description","category","config","type","command","args","env","credentials","envVar","placeholder","required","linear","jira","sentry","EMBEDDED_AGENT_PROVIDER","docker","figma","endpoint","postgres","isArg","mongodb","redis","supabase","exa","perplexity","context7","vercel","cloudflare","slack","notion","stripe","twilio","puppeteer","filesystem","Object","values","filter","t"],"mappings":"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"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "CastOAuthProvider", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return CastOAuthProvider;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _fs = /*#__PURE__*/ _interop_require_wildcard(require("fs"));
|
|
12
|
+
const _path = /*#__PURE__*/ _interop_require_wildcard(require("path"));
|
|
13
|
+
const _http = /*#__PURE__*/ _interop_require_wildcard(require("http"));
|
|
14
|
+
const _os = require("os");
|
|
15
|
+
const _child_process = require("child_process");
|
|
16
|
+
function _getRequireWildcardCache(nodeInterop) {
|
|
17
|
+
if (typeof WeakMap !== "function") return null;
|
|
18
|
+
var cacheBabelInterop = new WeakMap();
|
|
19
|
+
var cacheNodeInterop = new WeakMap();
|
|
20
|
+
return (_getRequireWildcardCache = function(nodeInterop) {
|
|
21
|
+
return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
|
|
22
|
+
})(nodeInterop);
|
|
23
|
+
}
|
|
24
|
+
function _interop_require_wildcard(obj, nodeInterop) {
|
|
25
|
+
if (!nodeInterop && obj && obj.__esModule) {
|
|
26
|
+
return obj;
|
|
27
|
+
}
|
|
28
|
+
if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
|
|
29
|
+
return {
|
|
30
|
+
default: obj
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
var cache = _getRequireWildcardCache(nodeInterop);
|
|
34
|
+
if (cache && cache.has(obj)) {
|
|
35
|
+
return cache.get(obj);
|
|
36
|
+
}
|
|
37
|
+
var newObj = {
|
|
38
|
+
__proto__: null
|
|
39
|
+
};
|
|
40
|
+
var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
|
|
41
|
+
for(var key in obj){
|
|
42
|
+
if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
43
|
+
var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
|
|
44
|
+
if (desc && (desc.get || desc.set)) {
|
|
45
|
+
Object.defineProperty(newObj, key, desc);
|
|
46
|
+
} else {
|
|
47
|
+
newObj[key] = obj[key];
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
newObj.default = obj;
|
|
52
|
+
if (cache) {
|
|
53
|
+
cache.set(obj, newObj);
|
|
54
|
+
}
|
|
55
|
+
return newObj;
|
|
56
|
+
}
|
|
57
|
+
const CAST_AUTH_DIR = _path.join((0, _os.homedir)(), '.cast', 'mcp-auth');
|
|
58
|
+
let CastOAuthProvider = class CastOAuthProvider {
|
|
59
|
+
get redirectUrl() {
|
|
60
|
+
return `http://127.0.0.1:${this.port}/callback`;
|
|
61
|
+
}
|
|
62
|
+
get clientMetadata() {
|
|
63
|
+
return {
|
|
64
|
+
client_name: 'Cast Code',
|
|
65
|
+
redirect_uris: [
|
|
66
|
+
this.redirectUrl
|
|
67
|
+
],
|
|
68
|
+
grant_types: [
|
|
69
|
+
'authorization_code',
|
|
70
|
+
'refresh_token'
|
|
71
|
+
],
|
|
72
|
+
response_types: [
|
|
73
|
+
'code'
|
|
74
|
+
],
|
|
75
|
+
token_endpoint_auth_method: 'none'
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
clientInformation() {
|
|
79
|
+
const file = _path.join(this.authDir, 'client.json');
|
|
80
|
+
if (!_fs.existsSync(file)) return undefined;
|
|
81
|
+
try {
|
|
82
|
+
return JSON.parse(_fs.readFileSync(file, 'utf-8'));
|
|
83
|
+
} catch {
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
saveClientInformation(info) {
|
|
88
|
+
_fs.writeFileSync(_path.join(this.authDir, 'client.json'), JSON.stringify(info, null, 2));
|
|
89
|
+
}
|
|
90
|
+
tokens() {
|
|
91
|
+
const file = _path.join(this.authDir, 'tokens.json');
|
|
92
|
+
if (!_fs.existsSync(file)) return undefined;
|
|
93
|
+
try {
|
|
94
|
+
return JSON.parse(_fs.readFileSync(file, 'utf-8'));
|
|
95
|
+
} catch {
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
saveTokens(tokens) {
|
|
100
|
+
_fs.writeFileSync(_path.join(this.authDir, 'tokens.json'), JSON.stringify(tokens, null, 2));
|
|
101
|
+
}
|
|
102
|
+
redirectToAuthorization(url) {
|
|
103
|
+
try {
|
|
104
|
+
(0, _child_process.spawn)('xdg-open', [
|
|
105
|
+
url.toString()
|
|
106
|
+
], {
|
|
107
|
+
detached: true,
|
|
108
|
+
stdio: 'ignore'
|
|
109
|
+
}).unref();
|
|
110
|
+
} catch {
|
|
111
|
+
// Silently ignore if xdg-open is not available
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
saveCodeVerifier(verifier) {
|
|
115
|
+
_fs.writeFileSync(_path.join(this.authDir, 'verifier.txt'), verifier);
|
|
116
|
+
}
|
|
117
|
+
codeVerifier() {
|
|
118
|
+
const file = _path.join(this.authDir, 'verifier.txt');
|
|
119
|
+
if (!_fs.existsSync(file)) throw new Error(`No PKCE code verifier saved for ${this.serverName}`);
|
|
120
|
+
return _fs.readFileSync(file, 'utf-8');
|
|
121
|
+
}
|
|
122
|
+
invalidateCredentials(scope) {
|
|
123
|
+
const remove = (name)=>{
|
|
124
|
+
const f = _path.join(this.authDir, name);
|
|
125
|
+
if (_fs.existsSync(f)) _fs.unlinkSync(f);
|
|
126
|
+
};
|
|
127
|
+
if (scope === 'all' || scope === 'tokens') remove('tokens.json');
|
|
128
|
+
if (scope === 'all' || scope === 'client') remove('client.json');
|
|
129
|
+
if (scope === 'all' || scope === 'verifier') remove('verifier.txt');
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Starts a local HTTP server on the callback port.
|
|
133
|
+
* Returns a Promise that resolves with the authorization code when the user
|
|
134
|
+
* completes the OAuth flow in their browser.
|
|
135
|
+
*
|
|
136
|
+
* @param onListening Optional callback fired when the server is ready (before opening browser)
|
|
137
|
+
*/ waitForCallback(onListening) {
|
|
138
|
+
return new Promise((resolve, reject)=>{
|
|
139
|
+
const server = _http.createServer((req, res)=>{
|
|
140
|
+
try {
|
|
141
|
+
const url = new URL(req.url ?? '/', `http://127.0.0.1:${this.port}`);
|
|
142
|
+
const code = url.searchParams.get('code');
|
|
143
|
+
const error = url.searchParams.get('error');
|
|
144
|
+
const successHtml = `
|
|
145
|
+
<html><body style="font-family:sans-serif;text-align:center;padding:40px;background:#f0fdf4">
|
|
146
|
+
<h2 style="color:#16a34a">✅ Autenticação concluída!</h2>
|
|
147
|
+
<p>Pode fechar esta aba e voltar ao terminal.</p>
|
|
148
|
+
</body></html>`;
|
|
149
|
+
const errorHtml = `
|
|
150
|
+
<html><body style="font-family:sans-serif;text-align:center;padding:40px;background:#fef2f2">
|
|
151
|
+
<h2 style="color:#dc2626">❌ Erro na autenticação</h2>
|
|
152
|
+
<p>${error ?? 'Erro desconhecido'}</p>
|
|
153
|
+
</body></html>`;
|
|
154
|
+
res.writeHead(200, {
|
|
155
|
+
'Content-Type': 'text/html; charset=utf-8'
|
|
156
|
+
});
|
|
157
|
+
if (code) {
|
|
158
|
+
res.end(successHtml);
|
|
159
|
+
server.close();
|
|
160
|
+
resolve(code);
|
|
161
|
+
} else {
|
|
162
|
+
res.end(errorHtml);
|
|
163
|
+
server.close();
|
|
164
|
+
reject(new Error(`OAuth error: ${error ?? 'unknown'}`));
|
|
165
|
+
}
|
|
166
|
+
} catch (e) {
|
|
167
|
+
server.close();
|
|
168
|
+
reject(e);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
171
|
+
server.on('error', (err)=>reject(err));
|
|
172
|
+
server.listen(this.port, '127.0.0.1', ()=>{
|
|
173
|
+
if (onListening) onListening();
|
|
174
|
+
});
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
constructor(serverName, port = 18090){
|
|
178
|
+
this.serverName = serverName;
|
|
179
|
+
this.authDir = _path.join(CAST_AUTH_DIR, serverName);
|
|
180
|
+
this.port = port;
|
|
181
|
+
_fs.mkdirSync(this.authDir, {
|
|
182
|
+
recursive: true
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
//# sourceMappingURL=cast-oauth-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../src/modules/mcp/services/cast-oauth-provider.ts"],"sourcesContent":["import * as fs from 'fs';\nimport * as path from 'path';\nimport * as http from 'http';\nimport { homedir } from 'os';\nimport { spawn } from 'child_process';\nimport type {\n OAuthClientProvider,\n OAuthClientMetadata,\n OAuthClientInformationMixed,\n OAuthTokens,\n} from '@modelcontextprotocol/sdk/client/auth.js';\n\nconst CAST_AUTH_DIR = path.join(homedir(), '.cast', 'mcp-auth');\n\n/**\n * Implements OAuthClientProvider for cast-code CLI.\n * Stores tokens and client info in ~/.cast/mcp-auth/<serverName>/\n */\nexport class CastOAuthProvider implements OAuthClientProvider {\n private readonly authDir: string;\n private readonly port: number;\n\n constructor(\n private readonly serverName: string,\n port = 18090,\n ) {\n this.authDir = path.join(CAST_AUTH_DIR, serverName);\n this.port = port;\n fs.mkdirSync(this.authDir, { recursive: true });\n }\n\n get redirectUrl(): string {\n return `http://127.0.0.1:${this.port}/callback`;\n }\n\n get clientMetadata(): OAuthClientMetadata {\n return {\n client_name: 'Cast Code',\n redirect_uris: [this.redirectUrl],\n grant_types: ['authorization_code', 'refresh_token'],\n response_types: ['code'],\n token_endpoint_auth_method: 'none',\n };\n }\n\n clientInformation(): OAuthClientInformationMixed | undefined {\n const file = path.join(this.authDir, 'client.json');\n if (!fs.existsSync(file)) return undefined;\n try {\n return JSON.parse(fs.readFileSync(file, 'utf-8'));\n } catch {\n return undefined;\n }\n }\n\n saveClientInformation(info: OAuthClientInformationMixed): void {\n fs.writeFileSync(\n path.join(this.authDir, 'client.json'),\n JSON.stringify(info, null, 2),\n );\n }\n\n tokens(): OAuthTokens | undefined {\n const file = path.join(this.authDir, 'tokens.json');\n if (!fs.existsSync(file)) return undefined;\n try {\n return JSON.parse(fs.readFileSync(file, 'utf-8'));\n } catch {\n return undefined;\n }\n }\n\n saveTokens(tokens: OAuthTokens): void {\n fs.writeFileSync(\n path.join(this.authDir, 'tokens.json'),\n JSON.stringify(tokens, null, 2),\n );\n }\n\n redirectToAuthorization(url: URL): void {\n try {\n spawn('xdg-open', [url.toString()], { detached: true, stdio: 'ignore' }).unref();\n } catch {\n // Silently ignore if xdg-open is not available\n }\n }\n\n saveCodeVerifier(verifier: string): void {\n fs.writeFileSync(path.join(this.authDir, 'verifier.txt'), verifier);\n }\n\n codeVerifier(): string {\n const file = path.join(this.authDir, 'verifier.txt');\n if (!fs.existsSync(file)) throw new Error(`No PKCE code verifier saved for ${this.serverName}`);\n return fs.readFileSync(file, 'utf-8');\n }\n\n invalidateCredentials(scope: 'all' | 'client' | 'tokens' | 'verifier'): void {\n const remove = (name: string) => {\n const f = path.join(this.authDir, name);\n if (fs.existsSync(f)) fs.unlinkSync(f);\n };\n if (scope === 'all' || scope === 'tokens') remove('tokens.json');\n if (scope === 'all' || scope === 'client') remove('client.json');\n if (scope === 'all' || scope === 'verifier') remove('verifier.txt');\n }\n\n /**\n * Starts a local HTTP server on the callback port.\n * Returns a Promise that resolves with the authorization code when the user\n * completes the OAuth flow in their browser.\n *\n * @param onListening Optional callback fired when the server is ready (before opening browser)\n */\n waitForCallback(onListening?: () => void): Promise<string> {\n return new Promise<string>((resolve, reject) => {\n const server = http.createServer((req, res) => {\n try {\n const url = new URL(req.url ?? '/', `http://127.0.0.1:${this.port}`);\n const code = url.searchParams.get('code');\n const error = url.searchParams.get('error');\n\n const successHtml = `\n <html><body style=\"font-family:sans-serif;text-align:center;padding:40px;background:#f0fdf4\">\n <h2 style=\"color:#16a34a\">✅ Autenticação concluída!</h2>\n <p>Pode fechar esta aba e voltar ao terminal.</p>\n </body></html>`;\n\n const errorHtml = `\n <html><body style=\"font-family:sans-serif;text-align:center;padding:40px;background:#fef2f2\">\n <h2 style=\"color:#dc2626\">❌ Erro na autenticação</h2>\n <p>${error ?? 'Erro desconhecido'}</p>\n </body></html>`;\n\n res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });\n\n if (code) {\n res.end(successHtml);\n server.close();\n resolve(code);\n } else {\n res.end(errorHtml);\n server.close();\n reject(new Error(`OAuth error: ${error ?? 'unknown'}`));\n }\n } catch (e) {\n server.close();\n reject(e);\n }\n });\n\n server.on('error', (err) => reject(err));\n server.listen(this.port, '127.0.0.1', () => {\n if (onListening) onListening();\n });\n });\n }\n}\n"],"names":["CastOAuthProvider","CAST_AUTH_DIR","path","join","homedir","redirectUrl","port","clientMetadata","client_name","redirect_uris","grant_types","response_types","token_endpoint_auth_method","clientInformation","file","authDir","fs","existsSync","undefined","JSON","parse","readFileSync","saveClientInformation","info","writeFileSync","stringify","tokens","saveTokens","redirectToAuthorization","url","spawn","toString","detached","stdio","unref","saveCodeVerifier","verifier","codeVerifier","Error","serverName","invalidateCredentials","scope","remove","name","f","unlinkSync","waitForCallback","onListening","Promise","resolve","reject","server","http","createServer","req","res","URL","code","searchParams","get","error","successHtml","errorHtml","writeHead","end","close","e","on","err","listen","mkdirSync","recursive"],"mappings":"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"}
|
|
@@ -11,6 +11,8 @@ Object.defineProperty(exports, "McpClientService", {
|
|
|
11
11
|
const _common = require("@nestjs/common");
|
|
12
12
|
const _events = require("events");
|
|
13
13
|
const _child_process = require("child_process");
|
|
14
|
+
const _auth = require("@modelcontextprotocol/sdk/client/auth.js");
|
|
15
|
+
const _castoauthprovider = require("./cast-oauth-provider");
|
|
14
16
|
function _ts_decorate(decorators, target, key, desc) {
|
|
15
17
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
16
18
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -103,59 +105,88 @@ let McpClientService = class McpClientService extends _events.EventEmitter {
|
|
|
103
105
|
}
|
|
104
106
|
async connectHttp(name, connection) {
|
|
105
107
|
const endpoint = connection.config.endpoint;
|
|
106
|
-
const headers = {
|
|
107
|
-
'Content-Type': 'application/json'
|
|
108
|
-
};
|
|
109
|
-
if (connection.config.env?.AUTH_TOKEN) {
|
|
110
|
-
headers['Authorization'] = `Bearer ${connection.config.env.AUTH_TOKEN}`;
|
|
111
|
-
}
|
|
112
108
|
try {
|
|
113
109
|
new URL(endpoint);
|
|
114
110
|
} catch {
|
|
115
111
|
throw new Error(`Invalid MCP HTTP endpoint: ${endpoint}`);
|
|
116
112
|
}
|
|
117
|
-
const
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
113
|
+
const headers = {
|
|
114
|
+
'Content-Type': 'application/json'
|
|
115
|
+
};
|
|
116
|
+
// Restore cached Bearer token if available (avoids re-running OAuth on reconnect)
|
|
117
|
+
const provider = new _castoauthprovider.CastOAuthProvider(name);
|
|
118
|
+
const cachedTokens = provider.tokens();
|
|
119
|
+
if (cachedTokens?.access_token) {
|
|
120
|
+
headers['Authorization'] = `Bearer ${cachedTokens.access_token}`;
|
|
121
|
+
}
|
|
122
|
+
const doFetch = async (body, hdrs = headers, timeoutMs = 15000)=>{
|
|
123
|
+
const controller = new AbortController();
|
|
124
|
+
const timer = setTimeout(()=>controller.abort(), timeoutMs);
|
|
125
|
+
try {
|
|
126
|
+
return await fetch(endpoint, {
|
|
127
|
+
method: 'POST',
|
|
128
|
+
headers: hdrs,
|
|
129
|
+
body: JSON.stringify(body),
|
|
130
|
+
signal: controller.signal
|
|
131
|
+
});
|
|
132
|
+
} finally{
|
|
133
|
+
clearTimeout(timer);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
const initBody = {
|
|
137
|
+
jsonrpc: '2.0',
|
|
138
|
+
id: this.nextId(),
|
|
139
|
+
method: 'initialize',
|
|
140
|
+
params: {
|
|
141
|
+
protocolVersion: '2024-11-05',
|
|
142
|
+
capabilities: {},
|
|
143
|
+
clientInfo: {
|
|
144
|
+
name: 'cast-code',
|
|
145
|
+
version: '1.0.0'
|
|
133
146
|
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
let initResponse = await doFetch(initBody);
|
|
150
|
+
// If 401: run full OAuth flow, then retry once with the new token
|
|
151
|
+
if (initResponse.status === 401) {
|
|
152
|
+
provider.invalidateCredentials('tokens');
|
|
153
|
+
let authResult = await (0, _auth.auth)(provider, {
|
|
154
|
+
serverUrl: endpoint
|
|
155
|
+
});
|
|
156
|
+
if (authResult === 'REDIRECT') {
|
|
157
|
+
this.emit('oauth:browser-opened', name, provider.redirectUrl);
|
|
158
|
+
const code = await provider.waitForCallback();
|
|
159
|
+
authResult = await (0, _auth.auth)(provider, {
|
|
160
|
+
serverUrl: endpoint,
|
|
161
|
+
authorizationCode: code
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
if (authResult !== 'AUTHORIZED') {
|
|
165
|
+
throw new Error(`OAuth failed for ${name}`);
|
|
166
|
+
}
|
|
167
|
+
const tokens = provider.tokens();
|
|
168
|
+
if (!tokens?.access_token) {
|
|
169
|
+
throw new Error(`No access token for ${name} after OAuth`);
|
|
170
|
+
}
|
|
171
|
+
headers['Authorization'] = `Bearer ${tokens.access_token}`;
|
|
172
|
+
initResponse = await doFetch(initBody);
|
|
173
|
+
}
|
|
138
174
|
if (!initResponse.ok) {
|
|
139
175
|
throw new Error(`HTTP MCP init failed: ${initResponse.status} ${initResponse.statusText}`);
|
|
140
176
|
}
|
|
141
|
-
const
|
|
142
|
-
|
|
143
|
-
const toolsResponse = await
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
id: this.nextId(),
|
|
149
|
-
method: 'tools/list',
|
|
150
|
-
params: {}
|
|
151
|
-
}),
|
|
152
|
-
signal: toolsController.signal
|
|
177
|
+
const sessionId = initResponse.headers.get('mcp-session-id');
|
|
178
|
+
if (sessionId) headers['Mcp-Session-Id'] = sessionId;
|
|
179
|
+
const toolsResponse = await doFetch({
|
|
180
|
+
jsonrpc: '2.0',
|
|
181
|
+
id: this.nextId(),
|
|
182
|
+
method: 'tools/list',
|
|
183
|
+
params: {}
|
|
153
184
|
});
|
|
154
|
-
clearTimeout(toolsTimeout);
|
|
155
185
|
if (toolsResponse.ok) {
|
|
156
186
|
const data = await toolsResponse.json();
|
|
157
187
|
connection.tools = data.result?.tools || data.tools || [];
|
|
158
188
|
}
|
|
189
|
+
connection._httpHeaders = headers;
|
|
159
190
|
}
|
|
160
191
|
sendRequest(name, method, params) {
|
|
161
192
|
const connection = this.connections.get(name);
|
|
@@ -202,12 +233,10 @@ let McpClientService = class McpClientService extends _events.EventEmitter {
|
|
|
202
233
|
}
|
|
203
234
|
if (connection.config.type === 'http') {
|
|
204
235
|
const endpoint = connection.config.endpoint;
|
|
205
|
-
|
|
236
|
+
// Use headers stored during connectHttp (includes Bearer token + session ID)
|
|
237
|
+
const headers = connection._httpHeaders ?? {
|
|
206
238
|
'Content-Type': 'application/json'
|
|
207
239
|
};
|
|
208
|
-
if (connection.config.env?.AUTH_TOKEN) {
|
|
209
|
-
headers['Authorization'] = `Bearer ${connection.config.env.AUTH_TOKEN}`;
|
|
210
|
-
}
|
|
211
240
|
const response = await fetch(endpoint, {
|
|
212
241
|
method: 'POST',
|
|
213
242
|
headers,
|
|
@@ -232,6 +261,9 @@ let McpClientService = class McpClientService extends _events.EventEmitter {
|
|
|
232
261
|
getStatus(name) {
|
|
233
262
|
return this.connections.get(name)?.status || 'unknown';
|
|
234
263
|
}
|
|
264
|
+
getAuthUrl(name) {
|
|
265
|
+
return this.connections.get(name)?.authUrl;
|
|
266
|
+
}
|
|
235
267
|
getAllStatuses() {
|
|
236
268
|
const statuses = new Map();
|
|
237
269
|
for (const [name, conn] of this.connections){
|