cast-code 1.0.1 → 1.0.3
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/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 +72 -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 +180 -51
- package/dist/modules/repl/services/commands/mcp-commands.service.js.map +1 -1
- package/package.json +2 -1
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":";;;;;;;;;;;QAmBaA;eAAAA;;QAghBGC;eAAAA;;QAIAC;eAAAA;;QARAC;eAAAA;;;AA5gBT,MAAMH,gBAA6C;IACxD,wBAAwB;IACxBI,QAAQ;QACNC,IAAI;QACJC,MAAM;QACNC,aAAa;QACbC,UAAU;QACVC,QAAQ;YACNC,MAAM;YACNC,SAAS;YACTC,MAAM;gBAAC;gBAAM;aAAsC;YACnDC,KAAK,CAAC;QACR;QACAC,aAAa;YACX;gBACER,MAAM;gBACNS,QAAQ;gBACRC,aAAa;gBACbC,UAAU;YACZ;SACD;IACH;IAEAC,QAAQ;QACNb,IAAI;QACJC,MAAM;QACNC,aAAa;QACbC,UAAU;QACVC,QAAQ;YACNC,MAAM;YACNC,SAAS;YACTC,MAAM;gBAAC;gBAAM;aAAiC;YAC9CC,KAAK,CAAC;QACR;QACAC,aAAa;YACX;gBACER,MAAM;gBACNS,QAAQ;gBACRC,aAAa;gBACbC,UAAU;YACZ;SACD;IACH;IAEAE,MAAM;QACJd,IAAI;QACJC,MAAM;QACNC,aAAa;QACbC,UAAU;QACVC,QAAQ;YACNC,MAAM;YACNC,SAAS;YACTC,MAAM;gBAAC;gBAAM;aAAqC;YAClDC,KAAK,CAAC;QACR;QACAC,aAAa;YACX;gBACER,MAAM;gBACNS,QAAQ;gBACRC,aAAa;gBACbC,UAAU;YACZ;YACA;gBACEX,MAAM;gBACNS,QAAQ;gBACRC,aAAa;gBACbC,UAAU;YACZ;YACA;gBACEX,MAAM;gBACNS,QAAQ;gBACRC,aAAa;gBACbC,UAAU;YACZ;SACD;IACH;IAEAG,QAAQ;QACNf,IAAI;QACJC,MAAM;QACNC,aAAa;QACbC,UAAU;QACVC,QAAQ;YACNC,MAAM;YACNC,SAAS;YACTC,MAAM;gBAAC;gBAAM;aAAqB;YAClCC,KAAK;gBACHQ,yBAAyB;YAC3B;QACF;QACAP,aAAa;YACX;gBACER,MAAM;gBACNS,QAAQ;gBACRC,aAAa;gBACbC,UAAU;YACZ;SACD;IACH;IAEAK,QAAQ;QACNjB,IAAI;QACJC,MAAM;QACNC,aAAa;QACbC,UAAU;QACVC,QAAQ;YACNC,MAAM;YACNC,SAAS;YACTC,MAAM;gBAAC;gBAAM;aAA8B;YAC3CC,KAAK,CAAC;QACR;QACAC,aAAa,EAAE;IACjB;IAEA,qBAAqB;IACrBS,OAAO;QACLlB,IAAI;QACJC,MAAM;QACNC,aAAa;QACbC,UAAU;QACVC,QAAQ;YACNC,MAAM;YACNc,UAAU;QACZ;QACAV,aAAa,EAAE;IACjB;IAEA,mBAAmB;IACnBW,UAAU;QACRpB,IAAI;QACJC,MAAM;QACNC,aAAa;QACbC,UAAU;QACVC,QAAQ;YACNC,MAAM;YACNC,SAAS;YACTC,MAAM;gBAAC;gBAAM;aAAwC;YACrDC,KAAK,CAAC;QACR;QACAC,aAAa;YACX;gBACER,MAAM;gBACNS,QAAQ;gBACRC,aAAa;gBACbC,UAAU;gBACVS,OAAO;YACT;SACD;IACH;IAEAC,SAAS;QACPtB,IAAI;QACJC,MAAM;QACNC,aAAa;QACbC,UAAU;QACVC,QAAQ;YACNC,MAAM;YACNC,SAAS;YACTC,MAAM;gBAAC;gBAAM;aAAiC;YAC9CC,KAAK,CAAC;QACR;QACAC,aAAa;YACX;gBACER,MAAM;gBACNS,QAAQ;gBACRC,aAAa;gBACbC,UAAU;YACZ;SACD;IACH;IAEAW,OAAO;QACLvB,IAAI;QACJC,MAAM;QACNC,aAAa;QACbC,UAAU;QACVC,QAAQ;YACNC,MAAM;YACNC,SAAS;YACTC,MAAM;gBAAC;gBAAM;aAAqC;YAClDC,KAAK,CAAC;QACR;QACAC,aAAa;YACX;gBACER,MAAM;gBACNS,QAAQ;gBACRC,aAAa;gBACbC,UAAU;YACZ;SACD;IACH;IAEAY,UAAU;QACRxB,IAAI;QACJC,MAAM;QACNC,aAAa;QACbC,UAAU;QACVC,QAAQ;YACNC,MAAM;YACNC,SAAS;YACTC,MAAM;gBAAC;gBAAM;aAA4B;YACzCC,KAAK,CAAC;QACR;QACAC,aAAa;YACX;gBACER,MAAM;gBACNS,QAAQ;gBACRC,aAAa;gBACbC,UAAU;YACZ;YACA;gBACEX,MAAM;gBACNS,QAAQ;gBACRC,aAAa;gBACbC,UAAU;YACZ;SACD;IACH;IAEA,qBAAqB;IACrB,gBAAgB;QACdZ,IAAI;QACJC,MAAM;QACNC,aAAa;QACbC,UAAU;QACVC,QAAQ;YACNC,MAAM;YACNC,SAAS;YACTC,MAAM;gBAAC;gBAAM;aAA4C;YACzDC,KAAK,CAAC;QACR;QACAC,aAAa;YACX;gBACER,MAAM;gBACNS,QAAQ;gBACRC,aAAa;gBACbC,UAAU;YACZ;SACD;IACH;IAEAa,KAAK;QACHzB,IAAI;QACJC,MAAM;QACNC,aAAa;QACbC,UAAU;QACVC,QAAQ;YACNC,MAAM;YACNC,SAAS;YACTC,MAAM;gBAAC;gBAAM;aAAiB;YAC9BC,KAAK,CAAC;QACR;QACAC,aAAa;YACX;gBACER,MAAM;gBACNS,QAAQ;gBACRC,aAAa;gBACbC,UAAU;YACZ;SACD;IACH;IAEAc,YAAY;QACV1B,IAAI;QACJC,MAAM;QACNC,aAAa;QACbC,UAAU;QACVC,QAAQ;YACNC,MAAM;YACNC,SAAS;YACTC,MAAM;gBAAC;gBAAM;aAA4B;YACzCC,KAAK,CAAC;QACR;QACAC,aAAa;YACX;gBACER,MAAM;gBACNS,QAAQ;gBACRC,aAAa;gBACbC,UAAU;YACZ;SACD;IACH;IAEAe,UAAU;QACR3B,IAAI;QACJC,MAAM;QACNC,aAAa;QACbC,UAAU;QACVC,QAAQ;YACNC,MAAM;YACNC,SAAS;YACTC,MAAM;gBAAC;gBAAM;aAAwB;YACrCC,KAAK,CAAC;QACR;QACAC,aAAa,EAAE;IACjB;IAEA,oBAAoB;IACpBmB,QAAQ;QACN5B,IAAI;QACJC,MAAM;QACNC,aAAa;QACbC,UAAU;QACVC,QAAQ;YACNC,MAAM;YACNC,SAAS;YACTC,MAAM;gBAAC;gBAAM;aAAsB;YACnCC,KAAK,CAAC;QACR;QACAC,aAAa,EAAE;IACjB;IAEAoB,YAAY;QACV7B,IAAI;QACJC,MAAM;QACNC,aAAa;QACbC,UAAU;QACVC,QAAQ;YACNC,MAAM;YACNc,UAAU;QACZ;QACAV,aAAa,EAAE;IACjB;IAEA,UAAU;QACRT,IAAI;QACJC,MAAM;QACNC,aAAa;QACbC,UAAU;QACVC,QAAQ;YACNC,MAAM;YACNC,SAAS;YACTC,MAAM;gBAAC;gBAAM;aAAa;YAC1BC,KAAK,CAAC;QACR;QACAC,aAAa;YACX;gBACER,MAAM;gBACNS,QAAQ;gBACRC,aAAa;gBACbC,UAAU;YACZ;YACA;gBACEX,MAAM;gBACNS,QAAQ;gBACRC,aAAa;gBACbC,UAAU;YACZ;YACA;gBACEX,MAAM;gBACNS,QAAQ;gBACRC,aAAa;gBACbC,UAAU;YACZ;SACD;IACH;IAEA,2BAA2B;IAC3BkB,OAAO;QACL9B,IAAI;QACJC,MAAM;QACNC,aAAa;QACbC,UAAU;QACVC,QAAQ;YACNC,MAAM;YACNC,SAAS;YACTC,MAAM;gBAAC;gBAAM;gBAA2B;gBAAe;aAAQ;YAC/DC,KAAK,CAAC;QACR;QACAC,aAAa;YACX;gBACER,MAAM;gBACNS,QAAQ;gBACRC,aAAa;gBACbC,UAAU;YACZ;YACA;gBACEX,MAAM;gBACNS,QAAQ;gBACRC,aAAa;gBACbC,UAAU;YACZ;SACD;IACH;IAEAmB,QAAQ;QACN/B,IAAI;QACJC,MAAM;QACNC,aAAa;QACbC,UAAU;QACVC,QAAQ;YACNC,MAAM;YACNC,SAAS;YACTC,MAAM;gBAAC;gBAAM;aAA8B;YAC3CC,KAAK,CAAC;QACR;QACAC,aAAa;YACX;gBACER,MAAM;gBACNS,QAAQ;gBACRC,aAAa;gBACbC,UAAU;YACZ;SACD;IACH;IAEA,gBAAgB;QACdZ,IAAI;QACJC,MAAM;QACNC,aAAa;QACbC,UAAU;QACVC,QAAQ;YACNC,MAAM;YACNC,SAAS;YACTC,MAAM;gBAAC;gBAAM;aAAsC;YACnDC,KAAK,CAAC;QACR;QACAC,aAAa,EAAE;IACjB;IAEA,eAAe;QACbT,IAAI;QACJC,MAAM;QACNC,aAAa;QACbC,UAAU;QACVC,QAAQ;YACNC,MAAM;YACNC,SAAS;YACTC,MAAM;gBAAC;gBAAM;aAAqC;YAClDC,KAAK,CAAC;QACR;QACAC,aAAa,EAAE;IACjB;IAEA,uBAAuB;IACvBuB,QAAQ;QACNhC,IAAI;QACJC,MAAM;QACNC,aAAa;QACbC,UAAU;QACVC,QAAQ;YACNC,MAAM;YACNC,SAAS;YACTC,MAAM;gBAAC;gBAAM;gBAAe;aAAc;YAC1CC,KAAK,CAAC;QACR;QACAC,aAAa;YACX;gBACER,MAAM;gBACNS,QAAQ;gBACRC,aAAa;gBACbC,UAAU;YACZ;SACD;IACH;IAEAqB,QAAQ;QACNjC,IAAI;QACJC,MAAM;QACNC,aAAa;QACbC,UAAU;QACVC,QAAQ;YACNC,MAAM;YACNC,SAAS;YACTC,MAAM;gBAAC;gBAAM;aAAoB;YACjCC,KAAK,CAAC;QACR;QACAC,aAAa;YACX;gBACER,MAAM;gBACNS,QAAQ;gBACRC,aAAa;gBACbC,UAAU;gBACVS,OAAO;YACT;YACA;gBACEpB,MAAM;gBACNS,QAAQ;gBACRC,aAAa;gBACbC,UAAU;gBACVS,OAAO;YACT;SACD;IACH;IAEA,sBAAsB;IACtBa,WAAW;QACTlC,IAAI;QACJC,MAAM;QACNC,aAAa;QACbC,UAAU;QACVC,QAAQ;YACNC,MAAM;YACNC,SAAS;YACTC,MAAM;gBAAC;gBAAM;aAAyC;YACtDC,KAAK,CAAC;QACR;QACAC,aAAa,EAAE;IACjB;IAEA,yBAAyB;IACzB0B,YAAY;QACVnC,IAAI;QACJC,MAAM;QACNC,aAAa;QACbC,UAAU;QACVC,QAAQ;YACNC,MAAM;YACNC,SAAS;YACTC,MAAM;gBAAC;gBAAM;aAA0C;YACvDC,KAAK,CAAC;QACR;QACAC,aAAa;YACX;gBACER,MAAM;gBACNS,QAAQ;gBACRC,aAAa;gBACbC,UAAU;gBACVS,OAAO;YACT;SACD;IACH;AACF;AAEO,SAASvB,uBAAuBK,QAAqB;IAC1D,OAAOiC,OAAOC,MAAM,CAAC1C,eAAe2C,MAAM,CAACC,CAAAA,IAAKA,EAAEpC,QAAQ,KAAKA;AACjE;AAEO,SAASP;IACd,OAAOwC,OAAOC,MAAM,CAAC1C;AACvB;AAEO,SAASE,YAAYG,EAAU;IACpC,OAAOL,aAAa,CAACK,GAAG;AAC1B"}
|
|
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,86 @@ 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
|
+
const provider = new _castoauthprovider.CastOAuthProvider(name);
|
|
117
|
+
const cachedTokens = provider.tokens();
|
|
118
|
+
if (cachedTokens?.access_token) {
|
|
119
|
+
headers['Authorization'] = `Bearer ${cachedTokens.access_token}`;
|
|
120
|
+
}
|
|
121
|
+
const doFetch = async (body, hdrs = headers, timeoutMs = 15000)=>{
|
|
122
|
+
const controller = new AbortController();
|
|
123
|
+
const timer = setTimeout(()=>controller.abort(), timeoutMs);
|
|
124
|
+
try {
|
|
125
|
+
return await fetch(endpoint, {
|
|
126
|
+
method: 'POST',
|
|
127
|
+
headers: hdrs,
|
|
128
|
+
body: JSON.stringify(body),
|
|
129
|
+
signal: controller.signal
|
|
130
|
+
});
|
|
131
|
+
} finally{
|
|
132
|
+
clearTimeout(timer);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
const initBody = {
|
|
136
|
+
jsonrpc: '2.0',
|
|
137
|
+
id: this.nextId(),
|
|
138
|
+
method: 'initialize',
|
|
139
|
+
params: {
|
|
140
|
+
protocolVersion: '2024-11-05',
|
|
141
|
+
capabilities: {},
|
|
142
|
+
clientInfo: {
|
|
143
|
+
name: 'cast-code',
|
|
144
|
+
version: '1.0.0'
|
|
133
145
|
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
146
|
+
}
|
|
147
|
+
};
|
|
148
|
+
let initResponse = await doFetch(initBody);
|
|
149
|
+
if (initResponse.status === 401) {
|
|
150
|
+
provider.invalidateCredentials('tokens');
|
|
151
|
+
let authResult = await (0, _auth.auth)(provider, {
|
|
152
|
+
serverUrl: endpoint
|
|
153
|
+
});
|
|
154
|
+
if (authResult === 'REDIRECT') {
|
|
155
|
+
this.emit('oauth:browser-opened', name, provider.redirectUrl);
|
|
156
|
+
const code = await provider.waitForCallback();
|
|
157
|
+
authResult = await (0, _auth.auth)(provider, {
|
|
158
|
+
serverUrl: endpoint,
|
|
159
|
+
authorizationCode: code
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
if (authResult !== 'AUTHORIZED') {
|
|
163
|
+
throw new Error(`OAuth failed for ${name}`);
|
|
164
|
+
}
|
|
165
|
+
const tokens = provider.tokens();
|
|
166
|
+
if (!tokens?.access_token) {
|
|
167
|
+
throw new Error(`No access token for ${name} after OAuth`);
|
|
168
|
+
}
|
|
169
|
+
headers['Authorization'] = `Bearer ${tokens.access_token}`;
|
|
170
|
+
initResponse = await doFetch(initBody);
|
|
171
|
+
}
|
|
138
172
|
if (!initResponse.ok) {
|
|
139
173
|
throw new Error(`HTTP MCP init failed: ${initResponse.status} ${initResponse.statusText}`);
|
|
140
174
|
}
|
|
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
|
|
175
|
+
const sessionId = initResponse.headers.get('mcp-session-id');
|
|
176
|
+
if (sessionId) headers['Mcp-Session-Id'] = sessionId;
|
|
177
|
+
const toolsResponse = await doFetch({
|
|
178
|
+
jsonrpc: '2.0',
|
|
179
|
+
id: this.nextId(),
|
|
180
|
+
method: 'tools/list',
|
|
181
|
+
params: {}
|
|
153
182
|
});
|
|
154
|
-
clearTimeout(toolsTimeout);
|
|
155
183
|
if (toolsResponse.ok) {
|
|
156
184
|
const data = await toolsResponse.json();
|
|
157
185
|
connection.tools = data.result?.tools || data.tools || [];
|
|
158
186
|
}
|
|
187
|
+
connection._httpHeaders = headers;
|
|
159
188
|
}
|
|
160
189
|
sendRequest(name, method, params) {
|
|
161
190
|
const connection = this.connections.get(name);
|
|
@@ -202,12 +231,9 @@ let McpClientService = class McpClientService extends _events.EventEmitter {
|
|
|
202
231
|
}
|
|
203
232
|
if (connection.config.type === 'http') {
|
|
204
233
|
const endpoint = connection.config.endpoint;
|
|
205
|
-
const headers = {
|
|
234
|
+
const headers = connection._httpHeaders ?? {
|
|
206
235
|
'Content-Type': 'application/json'
|
|
207
236
|
};
|
|
208
|
-
if (connection.config.env?.AUTH_TOKEN) {
|
|
209
|
-
headers['Authorization'] = `Bearer ${connection.config.env.AUTH_TOKEN}`;
|
|
210
|
-
}
|
|
211
237
|
const response = await fetch(endpoint, {
|
|
212
238
|
method: 'POST',
|
|
213
239
|
headers,
|
|
@@ -232,6 +258,9 @@ let McpClientService = class McpClientService extends _events.EventEmitter {
|
|
|
232
258
|
getStatus(name) {
|
|
233
259
|
return this.connections.get(name)?.status || 'unknown';
|
|
234
260
|
}
|
|
261
|
+
getAuthUrl(name) {
|
|
262
|
+
return this.connections.get(name)?.authUrl;
|
|
263
|
+
}
|
|
235
264
|
getAllStatuses() {
|
|
236
265
|
const statuses = new Map();
|
|
237
266
|
for (const [name, conn] of this.connections){
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/modules/mcp/services/mcp-client.service.ts"],"sourcesContent":["import { Injectable } from '@nestjs/common';\nimport { EventEmitter } from 'events';\nimport { spawn, ChildProcess } from 'child_process';\nimport { McpConfig, McpTool, McpConnection } from '../types';\n\n@Injectable()\nexport class McpClientService extends EventEmitter {\n private connections: Map<string, McpConnection> = new Map();\n private stdioBuffers: Map<string, string> = new Map();\n private requestIdCounter = 0;\n\n async connect(name: string, config: McpConfig): Promise<boolean> {\n if (this.connections.has(name)) {\n const existing = this.connections.get(name)!;\n if (existing.status === 'connected') {\n return true;\n }\n }\n\n const connection: McpConnection = {\n config,\n tools: [],\n status: 'connecting',\n };\n\n this.connections.set(name, connection);\n\n try {\n if (config.type === 'stdio' && config.command) {\n await this.connectStdio(name, connection);\n } else if (config.type === 'sse' && config.endpoint) {\n throw new Error('SSE transport not yet supported. Use stdio or http instead.');\n } else if (config.type === 'http' && config.endpoint) {\n await this.connectHttp(name, connection);\n }\n\n connection.status = 'connected';\n return true;\n } catch (error) {\n connection.status = 'error';\n return false;\n }\n }\n\n private async connectStdio(name: string, connection: McpConnection): Promise<void> {\n const { command, args = [], env = {} } = connection.config;\n\n const proc = spawn(command!, args, {\n env: { ...process.env, ...env },\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n\n connection.process = proc;\n this.stdioBuffers.set(name, '');\n\n proc.stdout?.on('data', (data: Buffer) => {\n const buffer = (this.stdioBuffers.get(name) || '') + data.toString();\n const lines = buffer.split('\\n');\n\n this.stdioBuffers.set(name, lines.pop() || '');\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n const parsed = JSON.parse(trimmed);\n this.emit(`response:${name}`, parsed);\n } catch {\n }\n }\n });\n\n proc.stderr?.on('data', (data: Buffer) => {\n const msg = data.toString().trim();\n if (msg && !msg.startsWith('Debugger') && !msg.startsWith('Warning')) {\n console.error(`MCP ${name} stderr:`, msg);\n }\n });\n\n proc.on('close', (code) => {\n connection.status = 'disconnected';\n this.stdioBuffers.delete(name);\n this.emit('disconnected', name);\n\n if (code !== null && code !== 0) {\n setTimeout(() => {\n this.reconnect(name).catch(() => {});\n }, 3000);\n }\n });\n\n await this.sendRequest(name, 'initialize', {\n protocolVersion: '2024-11-05',\n capabilities: {},\n clientInfo: { name: 'cast-code', version: '1.0.0' },\n });\n\n const toolsResponse = await this.sendRequest(name, 'tools/list', {});\n connection.tools = toolsResponse?.tools || [];\n }\n\n private async connectHttp(name: string, connection: McpConnection): Promise<void> {\n const endpoint = connection.config.endpoint!;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n if (connection.config.env?.AUTH_TOKEN) {\n headers['Authorization'] = `Bearer ${connection.config.env.AUTH_TOKEN}`;\n }\n\n try {\n new URL(endpoint);\n } catch {\n throw new Error(`Invalid MCP HTTP endpoint: ${endpoint}`);\n }\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 10000);\n\n const initResponse = await fetch(endpoint, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n jsonrpc: '2.0',\n id: this.nextId(),\n method: 'initialize',\n params: {\n protocolVersion: '2024-11-05',\n capabilities: {},\n clientInfo: { name: 'cast-code', version: '1.0.0' },\n },\n }),\n signal: controller.signal,\n });\n\n clearTimeout(timeout);\n\n if (!initResponse.ok) {\n throw new Error(`HTTP MCP init failed: ${initResponse.status} ${initResponse.statusText}`);\n }\n\n const toolsController = new AbortController();\n const toolsTimeout = setTimeout(() => toolsController.abort(), 10000);\n\n const toolsResponse = await fetch(endpoint, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n jsonrpc: '2.0',\n id: this.nextId(),\n method: 'tools/list',\n params: {},\n }),\n signal: toolsController.signal,\n });\n\n clearTimeout(toolsTimeout);\n\n if (toolsResponse.ok) {\n const data = await toolsResponse.json();\n connection.tools = data.result?.tools || data.tools || [];\n }\n }\n\n private sendRequest(\n name: string,\n method: string,\n params: Record<string, unknown>,\n ): Promise<any> {\n const connection = this.connections.get(name);\n\n if (!connection?.process) {\n return Promise.resolve(null);\n }\n\n return new Promise((resolve) => {\n const id = this.nextId();\n const request = JSON.stringify({ jsonrpc: '2.0', id, method, params });\n let resolved = false;\n\n const handler = (response: any) => {\n if (response.id === id && !resolved) {\n resolved = true;\n this.off(`response:${name}`, handler);\n resolve(response.result);\n }\n };\n\n this.on(`response:${name}`, handler);\n (connection.process as ChildProcess).stdin?.write(request + '\\n');\n\n setTimeout(() => {\n if (!resolved) {\n resolved = true;\n this.off(`response:${name}`, handler);\n resolve(null);\n }\n }, 15000);\n });\n }\n\n async callTool(\n mcpName: string,\n toolName: string,\n args: Record<string, unknown>,\n ): Promise<any> {\n const connection = this.connections.get(mcpName);\n\n if (!connection || connection.status !== 'connected') {\n throw new Error(`MCP ${mcpName} not connected`);\n }\n\n if (connection.config.type === 'stdio') {\n return this.sendRequest(mcpName, 'tools/call', { name: toolName, arguments: args });\n }\n\n if (connection.config.type === 'http') {\n const endpoint = connection.config.endpoint!;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n if (connection.config.env?.AUTH_TOKEN) {\n headers['Authorization'] = `Bearer ${connection.config.env.AUTH_TOKEN}`;\n }\n\n const response = await fetch(endpoint, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n jsonrpc: '2.0',\n id: this.nextId(),\n method: 'tools/call',\n params: { name: toolName, arguments: args },\n }),\n });\n\n const data = await response.json();\n return data.result || data;\n }\n\n return null;\n }\n\n getTools(name: string): McpTool[] {\n return this.connections.get(name)?.tools || [];\n }\n\n getStatus(name: string): string {\n return this.connections.get(name)?.status || 'unknown';\n }\n\n getAllStatuses(): Map<string, string> {\n const statuses = new Map<string, string>();\n for (const [name, conn] of this.connections) {\n statuses.set(name, conn.status);\n }\n return statuses;\n }\n\n private async reconnect(name: string): Promise<boolean> {\n const connection = this.connections.get(name);\n if (!connection) return false;\n\n if (connection.process) {\n try {\n (connection.process as ChildProcess).kill();\n } catch {}\n }\n\n connection.status = 'connecting';\n try {\n if (connection.config.type === 'stdio') {\n await this.connectStdio(name, connection);\n } else if (connection.config.type === 'http') {\n await this.connectHttp(name, connection);\n }\n connection.status = 'connected';\n this.emit('reconnected', name);\n return true;\n } catch {\n connection.status = 'error';\n return false;\n }\n }\n\n disconnect(name: string) {\n const connection = this.connections.get(name);\n\n if (connection?.process) {\n (connection.process as ChildProcess).kill();\n }\n\n this.stdioBuffers.delete(name);\n this.connections.delete(name);\n }\n\n disconnectAll() {\n for (const name of this.connections.keys()) {\n this.disconnect(name);\n }\n }\n\n private nextId(): string {\n return `${++this.requestIdCounter}`;\n }\n}\n"],"names":["McpClientService","EventEmitter","connect","name","config","connections","has","existing","get","status","connection","tools","set","type","command","connectStdio","endpoint","Error","connectHttp","error","args","env","proc","spawn","process","stdio","stdioBuffers","stdout","on","data","buffer","toString","lines","split","pop","line","trimmed","trim","parsed","JSON","parse","emit","stderr","msg","startsWith","console","code","delete","setTimeout","reconnect","catch","sendRequest","protocolVersion","capabilities","clientInfo","version","toolsResponse","headers","AUTH_TOKEN","URL","controller","AbortController","timeout","abort","initResponse","fetch","method","body","stringify","jsonrpc","id","nextId","params","signal","clearTimeout","ok","statusText","toolsController","toolsTimeout","json","result","Promise","resolve","request","resolved","handler","response","off","stdin","write","callTool","mcpName","toolName","arguments","getTools","getStatus","getAllStatuses","statuses","Map","conn","kill","disconnect","disconnectAll","keys","requestIdCounter"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/modules/mcp/services/mcp-client.service.ts"],"sourcesContent":["import { Injectable } from '@nestjs/common';\nimport { EventEmitter } from 'events';\nimport { spawn, ChildProcess } from 'child_process';\nimport { McpConfig, McpTool, McpConnection } from '../types';\nimport { auth } from '@modelcontextprotocol/sdk/client/auth.js';\nimport { CastOAuthProvider } from './cast-oauth-provider';\n\n@Injectable()\nexport class McpClientService extends EventEmitter {\n private connections: Map<string, McpConnection> = new Map();\n private stdioBuffers: Map<string, string> = new Map();\n private requestIdCounter = 0;\n\n async connect(name: string, config: McpConfig): Promise<boolean> {\n if (this.connections.has(name)) {\n const existing = this.connections.get(name)!;\n if (existing.status === 'connected') {\n return true;\n }\n }\n\n const connection: McpConnection = {\n config,\n tools: [],\n status: 'connecting',\n };\n\n this.connections.set(name, connection);\n\n try {\n if (config.type === 'stdio' && config.command) {\n await this.connectStdio(name, connection);\n } else if (config.type === 'sse' && config.endpoint) {\n throw new Error('SSE transport not yet supported. Use stdio or http instead.');\n } else if (config.type === 'http' && config.endpoint) {\n await this.connectHttp(name, connection);\n }\n\n connection.status = 'connected';\n return true;\n } catch (error) {\n connection.status = 'error';\n return false;\n }\n }\n\n private async connectStdio(name: string, connection: McpConnection): Promise<void> {\n const { command, args = [], env = {} } = connection.config;\n\n const proc = spawn(command!, args, {\n env: { ...process.env, ...env },\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n\n connection.process = proc;\n this.stdioBuffers.set(name, '');\n\n proc.stdout?.on('data', (data: Buffer) => {\n const buffer = (this.stdioBuffers.get(name) || '') + data.toString();\n const lines = buffer.split('\\n');\n\n this.stdioBuffers.set(name, lines.pop() || '');\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n try {\n const parsed = JSON.parse(trimmed);\n this.emit(`response:${name}`, parsed);\n } catch {\n }\n }\n });\n\n proc.stderr?.on('data', (data: Buffer) => {\n const msg = data.toString().trim();\n if (msg && !msg.startsWith('Debugger') && !msg.startsWith('Warning')) {\n console.error(`MCP ${name} stderr:`, msg);\n }\n });\n\n proc.on('close', (code) => {\n connection.status = 'disconnected';\n this.stdioBuffers.delete(name);\n this.emit('disconnected', name);\n\n if (code !== null && code !== 0) {\n setTimeout(() => {\n this.reconnect(name).catch(() => {});\n }, 3000);\n }\n });\n\n await this.sendRequest(name, 'initialize', {\n protocolVersion: '2024-11-05',\n capabilities: {},\n clientInfo: { name: 'cast-code', version: '1.0.0' },\n });\n\n const toolsResponse = await this.sendRequest(name, 'tools/list', {});\n connection.tools = toolsResponse?.tools || [];\n }\n\n private async connectHttp(name: string, connection: McpConnection): Promise<void> {\n const endpoint = connection.config.endpoint!;\n\n try {\n new URL(endpoint);\n } catch {\n throw new Error(`Invalid MCP HTTP endpoint: ${endpoint}`);\n }\n\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n\n const provider = new CastOAuthProvider(name);\n const cachedTokens = provider.tokens();\n if (cachedTokens?.access_token) {\n headers['Authorization'] = `Bearer ${cachedTokens.access_token}`;\n }\n\n const doFetch = async (body: object, hdrs = headers, timeoutMs = 15000): Promise<Response> => {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), timeoutMs);\n try {\n return await fetch(endpoint, {\n method: 'POST',\n headers: hdrs,\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n } finally {\n clearTimeout(timer);\n }\n };\n\n const initBody = {\n jsonrpc: '2.0',\n id: this.nextId(),\n method: 'initialize',\n params: {\n protocolVersion: '2024-11-05',\n capabilities: {},\n clientInfo: { name: 'cast-code', version: '1.0.0' },\n },\n };\n\n let initResponse = await doFetch(initBody);\n\n if (initResponse.status === 401) {\n provider.invalidateCredentials('tokens');\n\n let authResult = await auth(provider, { serverUrl: endpoint });\n\n if (authResult === 'REDIRECT') {\n this.emit('oauth:browser-opened', name, provider.redirectUrl);\n const code = await provider.waitForCallback();\n authResult = await auth(provider, { serverUrl: endpoint, authorizationCode: code });\n }\n\n if (authResult !== 'AUTHORIZED') {\n throw new Error(`OAuth failed for ${name}`);\n }\n\n const tokens = provider.tokens();\n if (!tokens?.access_token) {\n throw new Error(`No access token for ${name} after OAuth`);\n }\n\n headers['Authorization'] = `Bearer ${tokens.access_token}`;\n initResponse = await doFetch(initBody);\n }\n\n if (!initResponse.ok) {\n throw new Error(`HTTP MCP init failed: ${initResponse.status} ${initResponse.statusText}`);\n }\n\n const sessionId = initResponse.headers.get('mcp-session-id');\n if (sessionId) headers['Mcp-Session-Id'] = sessionId;\n\n const toolsResponse = await doFetch({\n jsonrpc: '2.0',\n id: this.nextId(),\n method: 'tools/list',\n params: {},\n });\n\n if (toolsResponse.ok) {\n const data = await toolsResponse.json();\n connection.tools = data.result?.tools || data.tools || [];\n }\n\n (connection as any)._httpHeaders = headers;\n }\n\n private sendRequest(\n name: string,\n method: string,\n params: Record<string, unknown>,\n ): Promise<any> {\n const connection = this.connections.get(name);\n\n if (!connection?.process) {\n return Promise.resolve(null);\n }\n\n return new Promise((resolve) => {\n const id = this.nextId();\n const request = JSON.stringify({ jsonrpc: '2.0', id, method, params });\n let resolved = false;\n\n const handler = (response: any) => {\n if (response.id === id && !resolved) {\n resolved = true;\n this.off(`response:${name}`, handler);\n resolve(response.result);\n }\n };\n\n this.on(`response:${name}`, handler);\n (connection.process as ChildProcess).stdin?.write(request + '\\n');\n\n setTimeout(() => {\n if (!resolved) {\n resolved = true;\n this.off(`response:${name}`, handler);\n resolve(null);\n }\n }, 15000);\n });\n }\n\n async callTool(\n mcpName: string,\n toolName: string,\n args: Record<string, unknown>,\n ): Promise<any> {\n const connection = this.connections.get(mcpName);\n\n if (!connection || connection.status !== 'connected') {\n throw new Error(`MCP ${mcpName} not connected`);\n }\n\n if (connection.config.type === 'stdio') {\n return this.sendRequest(mcpName, 'tools/call', { name: toolName, arguments: args });\n }\n\n if (connection.config.type === 'http') {\n const endpoint = connection.config.endpoint!;\n const headers: Record<string, string> = (connection as any)._httpHeaders ?? {\n 'Content-Type': 'application/json',\n };\n\n const response = await fetch(endpoint, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n jsonrpc: '2.0',\n id: this.nextId(),\n method: 'tools/call',\n params: { name: toolName, arguments: args },\n }),\n });\n\n const data = await response.json();\n return data.result || data;\n }\n\n return null;\n }\n\n getTools(name: string): McpTool[] {\n return this.connections.get(name)?.tools || [];\n }\n\n getStatus(name: string): string {\n return this.connections.get(name)?.status || 'unknown';\n }\n\n getAuthUrl(name: string): string | undefined {\n return this.connections.get(name)?.authUrl;\n }\n\n getAllStatuses(): Map<string, string> {\n const statuses = new Map<string, string>();\n for (const [name, conn] of this.connections) {\n statuses.set(name, conn.status);\n }\n return statuses;\n }\n\n private async reconnect(name: string): Promise<boolean> {\n const connection = this.connections.get(name);\n if (!connection) return false;\n\n if (connection.process) {\n try {\n (connection.process as ChildProcess).kill();\n } catch {}\n }\n\n connection.status = 'connecting';\n try {\n if (connection.config.type === 'stdio') {\n await this.connectStdio(name, connection);\n } else if (connection.config.type === 'http') {\n await this.connectHttp(name, connection);\n }\n connection.status = 'connected';\n this.emit('reconnected', name);\n return true;\n } catch {\n connection.status = 'error';\n return false;\n }\n }\n\n disconnect(name: string) {\n const connection = this.connections.get(name);\n\n if (connection?.process) {\n (connection.process as ChildProcess).kill();\n }\n\n this.stdioBuffers.delete(name);\n this.connections.delete(name);\n }\n\n disconnectAll() {\n for (const name of this.connections.keys()) {\n this.disconnect(name);\n }\n }\n\n private nextId(): string {\n return `${++this.requestIdCounter}`;\n }\n}\n"],"names":["McpClientService","EventEmitter","connect","name","config","connections","has","existing","get","status","connection","tools","set","type","command","connectStdio","endpoint","Error","connectHttp","error","args","env","proc","spawn","process","stdio","stdioBuffers","stdout","on","data","buffer","toString","lines","split","pop","line","trimmed","trim","parsed","JSON","parse","emit","stderr","msg","startsWith","console","code","delete","setTimeout","reconnect","catch","sendRequest","protocolVersion","capabilities","clientInfo","version","toolsResponse","URL","headers","provider","CastOAuthProvider","cachedTokens","tokens","access_token","doFetch","body","hdrs","timeoutMs","controller","AbortController","timer","abort","fetch","method","stringify","signal","clearTimeout","initBody","jsonrpc","id","nextId","params","initResponse","invalidateCredentials","authResult","auth","serverUrl","redirectUrl","waitForCallback","authorizationCode","ok","statusText","sessionId","json","result","_httpHeaders","Promise","resolve","request","resolved","handler","response","off","stdin","write","callTool","mcpName","toolName","arguments","getTools","getStatus","getAuthUrl","authUrl","getAllStatuses","statuses","Map","conn","kill","disconnect","disconnectAll","keys","requestIdCounter"],"mappings":"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"}
|