mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-25 07:00:48 +09:00
feat: mcp
This commit is contained in:
@@ -17,10 +17,12 @@
|
||||
"dependencies": {
|
||||
"@ai-sdk/anthropic": "^3.0.9",
|
||||
"@ai-sdk/google": "^3.0.6",
|
||||
"@ai-sdk/mcp": "^1.0.6",
|
||||
"@ai-sdk/openai": "^3.0.7",
|
||||
"@memoh/ai-gateway": "workspace:*",
|
||||
"@memoh/memory": "workspace:*",
|
||||
"@memoh/shared": "workspace:*",
|
||||
"@modelcontextprotocol/sdk": "^1.25.2",
|
||||
"ai": "^6.0.25",
|
||||
"dotenv": "^17.2.3",
|
||||
"sqlite3": "^5.1.7",
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { streamText, generateText, ModelMessage, stepCountIs, UserModelMessage } from 'ai'
|
||||
import { streamText, generateText, ModelMessage, stepCountIs, UserModelMessage, Tool } from 'ai'
|
||||
import { AgentParams } from './types'
|
||||
import { system, schedule as schedulePrompt } from './prompts'
|
||||
import { getMemoryTools, getScheduleTools, getMessageTools } from './tools'
|
||||
import { createChatGateway } from '@memoh/ai-gateway'
|
||||
import { Schedule } from '@memoh/shared'
|
||||
import { MCPConnection, Schedule } from '@memoh/shared'
|
||||
import { createMCPClient } from '@ai-sdk/mcp'
|
||||
import { StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js'
|
||||
|
||||
export const createAgent = (params: AgentParams) => {
|
||||
const messages: ModelMessage[] = []
|
||||
@@ -16,8 +18,37 @@ export const createAgent = (params: AgentParams) => {
|
||||
const currentPlatform = params.platforms
|
||||
? platforms.find(p => p.name === params.currentPlatform)?.name ?? 'Unknown Platform'
|
||||
: 'client'
|
||||
const mcpConnections = params.mcpConnections ?? []
|
||||
|
||||
const launchMCPConnections = async () => {
|
||||
const launch = async (connection: MCPConnection) => {
|
||||
if (connection.type === 'http' || connection.type === 'sse') {
|
||||
return await createMCPClient({
|
||||
transport: {
|
||||
url: connection.url,
|
||||
headers: connection.headers,
|
||||
type: connection.type,
|
||||
}
|
||||
})
|
||||
} else if (connection.type === 'stdio') {
|
||||
return await createMCPClient({
|
||||
transport: new StdioClientTransport({
|
||||
command: connection.command,
|
||||
args: connection.args,
|
||||
env: connection.env,
|
||||
cwd: connection.cwd,
|
||||
}),
|
||||
})
|
||||
}
|
||||
}
|
||||
const connections = await Promise.all(mcpConnections.map(launch))
|
||||
return connections.filter(connection => connection !== undefined)
|
||||
}
|
||||
|
||||
const getTools = async () => {
|
||||
const connections = await launchMCPConnections()
|
||||
const mcpTools = await Promise.all(connections.map(connection => connection.tools())) as Record<string, Tool>[]
|
||||
const tools = Object.assign({}, ...mcpTools)
|
||||
return {
|
||||
...getMemoryTools({
|
||||
searchMemory: params.onSearchMemory ?? (() => Promise.resolve([]))
|
||||
@@ -31,6 +62,7 @@ export const createAgent = (params: AgentParams) => {
|
||||
platforms,
|
||||
params.onSendMessage ?? (() => Promise.resolve())
|
||||
),
|
||||
...tools,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { MemoryUnit } from '@memoh/memory'
|
||||
import { ChatModel, Platform, Schedule } from '@memoh/shared'
|
||||
import { ChatModel, MCPConnection, Platform, Schedule } from '@memoh/shared'
|
||||
import { ModelMessage } from 'ai'
|
||||
|
||||
export interface SendMessageOptions {
|
||||
@@ -26,6 +26,8 @@ export interface AgentParams {
|
||||
|
||||
currentPlatform?: string
|
||||
|
||||
mcpConnections?: MCPConnection[]
|
||||
|
||||
onSendMessage?: (platform: string, options: SendMessageOptions) => Promise<void>
|
||||
|
||||
onReadMemory?: (from: Date, to: Date) => Promise<MemoryUnit[]>
|
||||
|
||||
@@ -3,6 +3,7 @@ import { createMemory, filterByTimestamp, MemoryUnit } from '@memoh/memory'
|
||||
import { ChatModel, EmbeddingModel, Platform, Schedule } from '@memoh/shared'
|
||||
import { createSchedule, deleteSchedule, getActiveSchedules } from '../schedule/service'
|
||||
import { getActivePlatforms, sendMessageToPlatform } from '../platform/service'
|
||||
import { getActiveMCPConnections } from '../mcp/service'
|
||||
|
||||
// Type for messages passed to onFinish callback
|
||||
type MessageType = Record<string, unknown>
|
||||
@@ -37,6 +38,7 @@ export async function createAgent(params: CreateAgentStreamParams) {
|
||||
})
|
||||
|
||||
const platforms = await getActivePlatforms()
|
||||
const mcpConnections = await getActiveMCPConnections(userId)
|
||||
|
||||
// Create agent
|
||||
const agent = createAgentService({
|
||||
@@ -45,6 +47,7 @@ export async function createAgent(params: CreateAgentStreamParams) {
|
||||
language: language || 'Same as user input',
|
||||
platforms: platforms as Platform[],
|
||||
currentPlatform: platform,
|
||||
mcpConnections,
|
||||
onSendMessage: async (platform: string, options) => {
|
||||
await sendMessageToPlatform(platform, {
|
||||
message: options.message,
|
||||
|
||||
@@ -3,8 +3,6 @@ import { z } from 'zod'
|
||||
// Stdio MCP 连接配置
|
||||
const StdioMCPConnectionSchema = z.object({
|
||||
type: z.literal('stdio'),
|
||||
name: z.string().min(1, 'Name is required').max(100),
|
||||
active: z.boolean(),
|
||||
command: z.string().min(1, 'Command is required'),
|
||||
args: z.array(z.string()),
|
||||
env: z.record(z.string(), z.string()),
|
||||
@@ -14,8 +12,6 @@ const StdioMCPConnectionSchema = z.object({
|
||||
// HTTP MCP 连接配置
|
||||
const HTTPMCPConnectionSchema = z.object({
|
||||
type: z.literal('http'),
|
||||
name: z.string().min(1, 'Name is required').max(100),
|
||||
active: z.boolean(),
|
||||
url: z.string().url('Invalid URL'),
|
||||
headers: z.record(z.string(), z.string()),
|
||||
})
|
||||
@@ -23,8 +19,6 @@ const HTTPMCPConnectionSchema = z.object({
|
||||
// SSE MCP 连接配置
|
||||
const SSEMCPConnectionSchema = z.object({
|
||||
type: z.literal('sse'),
|
||||
name: z.string().min(1, 'Name is required').max(100),
|
||||
active: z.boolean(),
|
||||
url: z.string().url('Invalid URL'),
|
||||
headers: z.record(z.string(), z.string()),
|
||||
})
|
||||
|
||||
@@ -3,6 +3,7 @@ import { mcpConnection } from '@memoh/db/schema'
|
||||
import { eq, desc, asc, sql } from 'drizzle-orm'
|
||||
import { calculateOffset, createPaginatedResult, type PaginatedResult } from '../../utils/pagination'
|
||||
import type { CreateMCPConnectionInput, UpdateMCPConnectionInput } from './model'
|
||||
import { MCPConnection } from '@memoh/shared'
|
||||
|
||||
/**
|
||||
* MCP Connection 列表返回类型
|
||||
@@ -77,14 +78,7 @@ export const getActiveMCPConnections = async (
|
||||
.where(eq(mcpConnection.user, userId))
|
||||
.orderBy(desc(mcpConnection.id))
|
||||
|
||||
return connections.filter(conn => conn.active).map(conn => ({
|
||||
id: conn.id,
|
||||
type: conn.type,
|
||||
name: conn.name,
|
||||
config: conn.config,
|
||||
active: conn.active,
|
||||
user: conn.user,
|
||||
}))
|
||||
return connections.filter(conn => conn.active).map(conn => conn.config) as MCPConnection[]
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,328 @@
|
||||
import type { Command } from 'commander'
|
||||
import chalk from 'chalk'
|
||||
import inquirer from 'inquirer'
|
||||
import ora from 'ora'
|
||||
import { table } from 'table'
|
||||
import * as mcpCore from '../../core/mcp'
|
||||
import { formatError } from '../../utils'
|
||||
import type { MCPConnectionConfig } from '../../types'
|
||||
|
||||
export function mcpCommands(program: Command) {
|
||||
program
|
||||
.command('list')
|
||||
.description('List all MCP connections')
|
||||
.action(async () => {
|
||||
try {
|
||||
const spinner = ora('Fetching MCP connections list...').start()
|
||||
|
||||
try {
|
||||
const connections = await mcpCore.listMCPConnections()
|
||||
spinner.succeed(chalk.green('MCP Connections List'))
|
||||
|
||||
if (connections.length === 0) {
|
||||
console.log(chalk.yellow('No MCP connections'))
|
||||
return
|
||||
}
|
||||
|
||||
const tableData = [
|
||||
['ID', 'Name', 'Type', 'Active'],
|
||||
...connections.map((conn) => [
|
||||
conn.id.substring(0, 8) + '...',
|
||||
conn.name,
|
||||
conn.type,
|
||||
conn.active ? chalk.green('Yes') : chalk.red('No'),
|
||||
]),
|
||||
]
|
||||
|
||||
console.log(table(tableData))
|
||||
} catch (error) {
|
||||
spinner.fail(chalk.red('Failed to fetch MCP connections list'))
|
||||
console.error(chalk.red(formatError(error)))
|
||||
process.exit(1)
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
const message = error instanceof Error ? error.message : String(error)
|
||||
console.error(chalk.red('Error:'), message)
|
||||
process.exit(1)
|
||||
}
|
||||
})
|
||||
|
||||
program
|
||||
.command('create')
|
||||
.description('Create MCP connection')
|
||||
.option('-n, --name <name>', 'Connection name')
|
||||
.option('-t, --type <type>', 'Connection type (stdio/http/sse)')
|
||||
.action(async (options) => {
|
||||
try {
|
||||
let { name, type } = options
|
||||
|
||||
// Get basic info
|
||||
if (!name || !type) {
|
||||
const basicAnswers = await inquirer.prompt([
|
||||
{
|
||||
type: 'input',
|
||||
name: 'name',
|
||||
message: 'Connection name:',
|
||||
when: !name,
|
||||
},
|
||||
{
|
||||
type: 'list',
|
||||
name: 'type',
|
||||
message: 'Connection type:',
|
||||
choices: ['stdio', 'http', 'sse'],
|
||||
when: !type,
|
||||
},
|
||||
])
|
||||
|
||||
name = name || basicAnswers.name
|
||||
type = type || basicAnswers.type
|
||||
}
|
||||
|
||||
let config: MCPConnectionConfig
|
||||
|
||||
// Get type-specific config
|
||||
if (type === 'stdio') {
|
||||
const stdioAnswers = await inquirer.prompt([
|
||||
{
|
||||
type: 'input',
|
||||
name: 'command',
|
||||
message: 'Command:',
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'args',
|
||||
message: 'Arguments (comma-separated, optional):',
|
||||
default: '',
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'cwd',
|
||||
message: 'Working directory:',
|
||||
default: process.cwd(),
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'env',
|
||||
message: 'Environment variables (key=value, comma-separated, optional):',
|
||||
default: '',
|
||||
},
|
||||
])
|
||||
|
||||
const args = stdioAnswers.args ? stdioAnswers.args.split(',').map((s: string) => s.trim()) : []
|
||||
const env: Record<string, string> = {}
|
||||
if (stdioAnswers.env) {
|
||||
stdioAnswers.env.split(',').forEach((pair: string) => {
|
||||
const [key, value] = pair.split('=').map((s: string) => s.trim())
|
||||
if (key && value) {
|
||||
env[key] = value
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
config = {
|
||||
type: 'stdio',
|
||||
command: stdioAnswers.command,
|
||||
args,
|
||||
env,
|
||||
cwd: stdioAnswers.cwd,
|
||||
}
|
||||
} else if (type === 'http' || type === 'sse') {
|
||||
const httpAnswers = await inquirer.prompt([
|
||||
{
|
||||
type: 'input',
|
||||
name: 'url',
|
||||
message: 'URL:',
|
||||
},
|
||||
{
|
||||
type: 'input',
|
||||
name: 'headers',
|
||||
message: 'Headers (key=value, comma-separated, optional):',
|
||||
default: '',
|
||||
},
|
||||
])
|
||||
|
||||
const headers: Record<string, string> = {}
|
||||
if (httpAnswers.headers) {
|
||||
httpAnswers.headers.split(',').forEach((pair: string) => {
|
||||
const [key, value] = pair.split('=').map((s: string) => s.trim())
|
||||
if (key && value) {
|
||||
headers[key] = value
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
config = {
|
||||
type: type as 'http' | 'sse',
|
||||
url: httpAnswers.url,
|
||||
headers,
|
||||
}
|
||||
} else {
|
||||
console.error(chalk.red('Invalid connection type'))
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const { active } = await inquirer.prompt([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'active',
|
||||
message: 'Activate connection?',
|
||||
default: true,
|
||||
},
|
||||
])
|
||||
|
||||
const spinner = ora('Creating MCP connection...').start()
|
||||
|
||||
try {
|
||||
const connection = await mcpCore.createMCPConnection({
|
||||
name,
|
||||
config,
|
||||
active,
|
||||
})
|
||||
|
||||
spinner.succeed(chalk.green('MCP connection created successfully'))
|
||||
console.log(chalk.blue(`Name: ${connection.name}`))
|
||||
console.log(chalk.blue(`Type: ${connection.type}`))
|
||||
console.log(chalk.blue(`ID: ${connection.id}`))
|
||||
} catch (error) {
|
||||
spinner.fail(chalk.red('Failed to create MCP connection'))
|
||||
console.error(chalk.red(formatError(error)))
|
||||
process.exit(1)
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
const message = error instanceof Error ? error.message : String(error)
|
||||
console.error(chalk.red('Error:'), message)
|
||||
process.exit(1)
|
||||
}
|
||||
})
|
||||
|
||||
program
|
||||
.command('get <id>')
|
||||
.description('Get MCP connection details')
|
||||
.action(async (id) => {
|
||||
try {
|
||||
const spinner = ora('Fetching MCP connection details...').start()
|
||||
|
||||
try {
|
||||
const connection = await mcpCore.getMCPConnection(id)
|
||||
spinner.succeed(chalk.green('MCP Connection Details'))
|
||||
console.log(chalk.blue(`ID: ${connection.id}`))
|
||||
console.log(chalk.blue(`Name: ${connection.name}`))
|
||||
console.log(chalk.blue(`Type: ${connection.type}`))
|
||||
console.log(
|
||||
chalk.blue(`Active: ${connection.active ? chalk.green('Yes') : chalk.red('No')}`)
|
||||
)
|
||||
console.log(chalk.blue(`Config:`))
|
||||
console.log(JSON.stringify(connection.config, null, 2))
|
||||
} catch (error) {
|
||||
spinner.fail(chalk.red('Failed to fetch MCP connection'))
|
||||
console.error(chalk.red(formatError(error)))
|
||||
process.exit(1)
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
const message = error instanceof Error ? error.message : String(error)
|
||||
console.error(chalk.red('Error:'), message)
|
||||
process.exit(1)
|
||||
}
|
||||
})
|
||||
|
||||
program
|
||||
.command('update <id>')
|
||||
.description('Update MCP connection')
|
||||
.option('-n, --name <name>', 'Connection name')
|
||||
.option('-a, --active <boolean>', 'Active status (true/false)')
|
||||
.action(async (id, options) => {
|
||||
try {
|
||||
const updates: {
|
||||
name?: string
|
||||
active?: boolean
|
||||
} = {}
|
||||
|
||||
if (options.name) updates.name = options.name
|
||||
if (options.active !== undefined) {
|
||||
updates.active = options.active === 'true' || options.active === true
|
||||
}
|
||||
|
||||
if (Object.keys(updates).length === 0) {
|
||||
console.log(chalk.yellow('No update parameters provided'))
|
||||
console.log(chalk.yellow('Note: Config updates are not yet supported via CLI'))
|
||||
return
|
||||
}
|
||||
|
||||
const spinner = ora('Updating MCP connection...').start()
|
||||
|
||||
try {
|
||||
await mcpCore.updateMCPConnection(id, updates)
|
||||
spinner.succeed(chalk.green('MCP connection updated'))
|
||||
} catch (error) {
|
||||
spinner.fail(chalk.red('Failed to update MCP connection'))
|
||||
console.error(chalk.red(formatError(error)))
|
||||
process.exit(1)
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
const message = error instanceof Error ? error.message : String(error)
|
||||
console.error(chalk.red('Error:'), message)
|
||||
process.exit(1)
|
||||
}
|
||||
})
|
||||
|
||||
program
|
||||
.command('delete <id>')
|
||||
.description('Delete MCP connection')
|
||||
.action(async (id) => {
|
||||
try {
|
||||
const { confirm } = await inquirer.prompt([
|
||||
{
|
||||
type: 'confirm',
|
||||
name: 'confirm',
|
||||
message: chalk.yellow(`Are you sure you want to delete MCP connection ${id}?`),
|
||||
default: false,
|
||||
},
|
||||
])
|
||||
|
||||
if (!confirm) {
|
||||
console.log(chalk.yellow('Cancelled'))
|
||||
return
|
||||
}
|
||||
|
||||
const spinner = ora('Deleting MCP connection...').start()
|
||||
|
||||
try {
|
||||
await mcpCore.deleteMCPConnection(id)
|
||||
spinner.succeed(chalk.green('MCP connection deleted'))
|
||||
} catch (error) {
|
||||
spinner.fail(chalk.red('Failed to delete MCP connection'))
|
||||
console.error(chalk.red(formatError(error)))
|
||||
process.exit(1)
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
const message = error instanceof Error ? error.message : String(error)
|
||||
console.error(chalk.red('Error:'), message)
|
||||
process.exit(1)
|
||||
}
|
||||
})
|
||||
|
||||
program
|
||||
.command('toggle <id>')
|
||||
.description('Toggle MCP connection active status')
|
||||
.action(async (id) => {
|
||||
try {
|
||||
const spinner = ora('Toggling connection status...').start()
|
||||
|
||||
try {
|
||||
const newStatus = await mcpCore.toggleMCPConnection(id)
|
||||
spinner.succeed(
|
||||
chalk.green(`Connection ${newStatus ? 'activated' : 'deactivated'}`)
|
||||
)
|
||||
} catch (error) {
|
||||
spinner.fail(chalk.red('Failed to toggle connection'))
|
||||
console.error(chalk.red(formatError(error)))
|
||||
process.exit(1)
|
||||
}
|
||||
} catch (error: unknown) {
|
||||
const message = error instanceof Error ? error.message : String(error)
|
||||
console.error(chalk.red('Error:'), message)
|
||||
process.exit(1)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import { agentCommands, startInteractiveMode } from './commands/agent'
|
||||
import { memoryCommands } from './commands/memory'
|
||||
import { configCommands } from './commands/config'
|
||||
import { scheduleCommands } from './commands/schedule'
|
||||
import { mcpCommands } from './commands/mcp'
|
||||
import { debugCommands } from './commands/debug'
|
||||
|
||||
const program = new Command()
|
||||
@@ -51,6 +52,10 @@ configCommands(config)
|
||||
const schedule = program.command('schedule').description('Schedule management')
|
||||
scheduleCommands(schedule)
|
||||
|
||||
// MCP management commands
|
||||
const mcp = program.command('mcp').description('MCP connection management')
|
||||
mcpCommands(mcp)
|
||||
|
||||
// Debug commands
|
||||
const debug = program.command('debug').description('Debug tools')
|
||||
debugCommands(debug)
|
||||
|
||||
@@ -103,6 +103,18 @@ export {
|
||||
type UpdateScheduleParams,
|
||||
} from './schedule'
|
||||
|
||||
// MCP
|
||||
export {
|
||||
listMCPConnections,
|
||||
createMCPConnection,
|
||||
getMCPConnection,
|
||||
updateMCPConnection,
|
||||
deleteMCPConnection,
|
||||
toggleMCPConnection,
|
||||
type CreateMCPConnectionParams,
|
||||
type UpdateMCPConnectionParams,
|
||||
} from './mcp'
|
||||
|
||||
// Settings
|
||||
export {
|
||||
getSettings,
|
||||
|
||||
@@ -0,0 +1,212 @@
|
||||
import { createClient, requireAuth } from './client'
|
||||
import type { MCPConnection, MCPConnectionConfig } from '../types'
|
||||
|
||||
export interface CreateMCPConnectionParams {
|
||||
name: string
|
||||
config: MCPConnectionConfig
|
||||
active?: boolean
|
||||
}
|
||||
|
||||
export interface UpdateMCPConnectionParams {
|
||||
name?: string
|
||||
config?: MCPConnectionConfig
|
||||
active?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* List all MCP connections
|
||||
*/
|
||||
export async function listMCPConnections(): Promise<MCPConnection[]> {
|
||||
requireAuth()
|
||||
const client = createClient()
|
||||
|
||||
const response = await client.mcp.get()
|
||||
|
||||
if (response.error) {
|
||||
const errorValue = response.error.value
|
||||
if (typeof errorValue === 'string') {
|
||||
throw new Error(errorValue)
|
||||
} else if (typeof errorValue === 'object' && errorValue !== null) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const errorObj = errorValue as any
|
||||
const errorMsg = errorObj.error || errorObj.message || JSON.stringify(errorValue)
|
||||
throw new Error(errorMsg)
|
||||
}
|
||||
throw new Error('Failed to fetch MCP connections list')
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const data = response.data as any
|
||||
if (data?.success && data?.data) {
|
||||
return data.data
|
||||
}
|
||||
|
||||
throw new Error('Failed to fetch MCP connections list')
|
||||
}
|
||||
|
||||
/**
|
||||
* Create MCP connection
|
||||
*/
|
||||
export async function createMCPConnection(params: CreateMCPConnectionParams): Promise<MCPConnection> {
|
||||
requireAuth()
|
||||
const client = createClient()
|
||||
|
||||
const payload = {
|
||||
name: params.name,
|
||||
config: params.config,
|
||||
active: params.active ?? true,
|
||||
}
|
||||
|
||||
const response = await client.mcp.post(payload)
|
||||
|
||||
if (response.error) {
|
||||
const errorValue = response.error.value
|
||||
if (typeof errorValue === 'string') {
|
||||
throw new Error(errorValue)
|
||||
} else if (typeof errorValue === 'object' && errorValue !== null) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const errorObj = errorValue as any
|
||||
const errorMsg = errorObj.error || errorObj.message || JSON.stringify(errorValue)
|
||||
throw new Error(errorMsg)
|
||||
}
|
||||
throw new Error('Failed to create MCP connection')
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const data = response.data as any
|
||||
if (data?.success && data?.data) {
|
||||
return data.data
|
||||
}
|
||||
|
||||
throw new Error('Failed to create MCP connection')
|
||||
}
|
||||
|
||||
/**
|
||||
* Get MCP connection by ID
|
||||
*/
|
||||
export async function getMCPConnection(id: string): Promise<MCPConnection> {
|
||||
requireAuth()
|
||||
const client = createClient()
|
||||
|
||||
const response = await client.mcp({ id }).get()
|
||||
|
||||
if (response.error) {
|
||||
const errorValue = response.error.value
|
||||
if (typeof errorValue === 'string') {
|
||||
throw new Error(errorValue)
|
||||
} else if (typeof errorValue === 'object' && errorValue !== null) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const errorObj = errorValue as any
|
||||
const errorMsg = errorObj.error || errorObj.message || JSON.stringify(errorValue)
|
||||
throw new Error(errorMsg)
|
||||
}
|
||||
throw new Error('Failed to fetch MCP connection')
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const data = response.data as any
|
||||
if (data?.success && data?.data) {
|
||||
return data.data
|
||||
}
|
||||
|
||||
throw new Error('Failed to fetch MCP connection')
|
||||
}
|
||||
|
||||
/**
|
||||
* Update MCP connection
|
||||
*/
|
||||
export async function updateMCPConnection(id: string, params: UpdateMCPConnectionParams): Promise<void> {
|
||||
requireAuth()
|
||||
const client = createClient()
|
||||
|
||||
const response = await client.mcp({ id }).put(params)
|
||||
|
||||
if (response.error) {
|
||||
const errorValue = response.error.value
|
||||
if (typeof errorValue === 'string') {
|
||||
throw new Error(errorValue)
|
||||
} else if (typeof errorValue === 'object' && errorValue !== null) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const errorObj = errorValue as any
|
||||
const errorMsg = errorObj.error || errorObj.message || JSON.stringify(errorValue)
|
||||
throw new Error(errorMsg)
|
||||
}
|
||||
throw new Error('Failed to update MCP connection')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete MCP connection
|
||||
*/
|
||||
export async function deleteMCPConnection(id: string): Promise<void> {
|
||||
requireAuth()
|
||||
const client = createClient()
|
||||
|
||||
const response = await client.mcp({ id }).delete()
|
||||
|
||||
if (response.error) {
|
||||
const errorValue = response.error.value
|
||||
if (typeof errorValue === 'string') {
|
||||
throw new Error(errorValue)
|
||||
} else if (typeof errorValue === 'object' && errorValue !== null) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const errorObj = errorValue as any
|
||||
const errorMsg = errorObj.error || errorObj.message || JSON.stringify(errorValue)
|
||||
throw new Error(errorMsg)
|
||||
}
|
||||
throw new Error('Failed to delete MCP connection')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle MCP connection active status
|
||||
*/
|
||||
export async function toggleMCPConnection(id: string): Promise<boolean> {
|
||||
requireAuth()
|
||||
const client = createClient()
|
||||
|
||||
// First get current status
|
||||
const getResponse = await client.mcp({ id }).get()
|
||||
|
||||
if (getResponse.error) {
|
||||
const errorValue = getResponse.error.value
|
||||
if (typeof errorValue === 'string') {
|
||||
throw new Error(errorValue)
|
||||
} else if (typeof errorValue === 'object' && errorValue !== null) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const errorObj = errorValue as any
|
||||
const errorMsg = errorObj.error || errorObj.message || JSON.stringify(errorValue)
|
||||
throw new Error(errorMsg)
|
||||
}
|
||||
throw new Error('Failed to get MCP connection')
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const getData = getResponse.data as any
|
||||
if (getData?.success && getData?.data) {
|
||||
const currentActive = getData.data.active
|
||||
|
||||
// Update status
|
||||
const updateResponse = await client.mcp({ id }).put({
|
||||
active: !currentActive,
|
||||
})
|
||||
|
||||
if (updateResponse.error) {
|
||||
const errorValue = updateResponse.error.value
|
||||
if (typeof errorValue === 'string') {
|
||||
throw new Error(errorValue)
|
||||
} else if (typeof errorValue === 'object' && errorValue !== null) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const errorObj = errorValue as any
|
||||
const errorMsg = errorObj.error || errorObj.message || JSON.stringify(errorValue)
|
||||
throw new Error(errorMsg)
|
||||
}
|
||||
throw new Error('Failed to update MCP connection')
|
||||
}
|
||||
|
||||
return !currentActive
|
||||
}
|
||||
|
||||
throw new Error('Failed to toggle MCP connection status')
|
||||
}
|
||||
|
||||
@@ -79,3 +79,37 @@ export interface Platform {
|
||||
updatedAt: string
|
||||
}
|
||||
|
||||
export interface MCPConnection {
|
||||
id: string
|
||||
type: string
|
||||
name: string
|
||||
config: MCPConnectionConfig
|
||||
active: boolean
|
||||
user: string
|
||||
}
|
||||
|
||||
export type MCPConnectionConfig =
|
||||
| StdioMCPConnection
|
||||
| HTTPMCPConnection
|
||||
| SSEMCPConnection
|
||||
|
||||
export interface StdioMCPConnection {
|
||||
type: 'stdio'
|
||||
command: string
|
||||
args: string[]
|
||||
env: Record<string, string>
|
||||
cwd: string
|
||||
}
|
||||
|
||||
export interface HTTPMCPConnection {
|
||||
type: 'http'
|
||||
url: string
|
||||
headers: Record<string, string>
|
||||
}
|
||||
|
||||
export interface SSEMCPConnection {
|
||||
type: 'sse'
|
||||
url: string
|
||||
headers: Record<string, string>
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
export * from './model'
|
||||
export * from './schedule'
|
||||
export * from './platform'
|
||||
export * from './platform'
|
||||
export * from './mcp'
|
||||
@@ -1,7 +1,6 @@
|
||||
export interface BaseMCPConnection {
|
||||
type: string
|
||||
name: string
|
||||
active: boolean
|
||||
}
|
||||
|
||||
export interface StdioMCPConnection extends BaseMCPConnection {
|
||||
|
||||
Reference in New Issue
Block a user