- 
                Notifications
    
You must be signed in to change notification settings  - Fork 2.3k
 
Feature/mcp integration #1231
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feature/mcp integration #1231
Changes from 4 commits
6c7aaa5
              ed6b8d0
              fdaadd8
              adbfc2e
              e807cf3
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,112 @@ | ||||||
| 'use client' | ||||||
| 
     | 
||||||
| import { useEffect, useState } from 'react' | ||||||
| import { getMcpTools } from '@/lib/mcp' | ||||||
| 
     | 
||||||
| interface McpTool { | ||||||
| id: string | ||||||
| name: string | ||||||
| description: string | ||||||
| icon: React.ComponentType<any> | ||||||
                
       | 
||||||
| bgColor: string | ||||||
| type: string | ||||||
| server: string | ||||||
| } | ||||||
| 
     | 
||||||
| interface McpToolsProps { | ||||||
| onToolClick: (toolType: string) => void | ||||||
| } | ||||||
| 
     | 
||||||
| export function McpTools({ onToolClick }: McpToolsProps) { | ||||||
| const [mcpTools, setMcpTools] = useState<McpTool[]>([]) | ||||||
| const [isLoading, setIsLoading] = useState(true) | ||||||
| const [error, setError] = useState<string | null>(null) | ||||||
| 
     | 
||||||
| async function fetchMcpTools() { | ||||||
| setIsLoading(true) | ||||||
| setError(null) | ||||||
| try { | ||||||
| const tools = await getMcpTools() | ||||||
| setMcpTools(tools) | ||||||
| } catch (error) { | ||||||
                
       | 
||||||
| } catch (error) { | |
| } catch (err) { | 
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| import { promises as fs } from 'fs'; | ||
| import path from 'path'; | ||
| import { z } from 'zod'; | ||
| import { ApiIcon } from '@/components/icons'; | ||
| 
     | 
||
| const McpToolSchema = z.object({ | ||
| id: z.string(), | ||
| name: z.string(), | ||
| description: z.string(), | ||
| icon: z.any(), | ||
                
       | 
||
| bgColor: z.string(), | ||
| type: z.string(), | ||
| server: z.string(), | ||
| }); | ||
| 
     | 
||
| export type McpTool = z.infer<typeof McpToolSchema>; | ||
| 
     | 
||
| const McpoConfigSchema = z.object({ | ||
| mcpServers: z.record(z.object({ | ||
| command: z.string(), | ||
| args: z.array(z.string()), | ||
| url: z.string().optional(), | ||
| })), | ||
| }); | ||
| 
     | 
||
| async function readMcpoConfig() { | ||
| const configPath = path.resolve(process.cwd(), 'mcpo-config.json'); | ||
| try { | ||
| const fileContent = await fs.readFile(configPath, 'utf-8'); | ||
| const config = JSON.parse(fileContent); | ||
| return McpoConfigSchema.parse(config); | ||
| } catch (error) { | ||
| console.error('Error reading or parsing mcpo-config.json:', error); | ||
| throw new Error('Could not read or parse mcpo-config.json'); | ||
| } | ||
| } | ||
| 
     | 
||
| export async function getMcpTools(): Promise<McpTool[]> { | ||
| const config = await readMcpoConfig(); | ||
| const allTools: McpTool[] = []; | ||
| 
     | 
||
| for (const serverName in config.mcpServers) { | ||
| const serverConfig = config.mcpServers[serverName]; | ||
| // For now, let's assume a default URL if not provided. | ||
| // This will be improved in the dynamic configuration step. | ||
| const openapi_url = serverConfig.url || `http://localhost:8000/openapi.json`; | ||
| 
     | 
||
| try { | ||
| const response = await fetch(openapi_url); | ||
| if (!response.ok) { | ||
| console.error(`Error fetching OpenAPI schema from ${serverName}: ${response.statusText}`); | ||
| continue; | ||
| } | ||
| const openapi_spec = await response.json(); | ||
| 
     | 
||
| const serverTools = transformOpenAPIToMcpTools(openapi_spec, serverName); | ||
| allTools.push(...serverTools); | ||
| 
     | 
||
| } catch (error) { | ||
| console.error(`Error fetching or parsing OpenAPI schema from ${serverName}:`, error); | ||
| } | ||
| } | ||
| 
     | 
||
| return allTools; | ||
| } | ||
| 
     | 
||
| function transformOpenAPIToMcpTools(openapi_spec: any, serverName: string): McpTool[] { | ||
                
       | 
||
| const tools: McpTool[] = []; | ||
| if (!openapi_spec.paths) { | ||
| return tools; | ||
| } | ||
| 
     | 
||
| for (const path in openapi_spec.paths) { | ||
| const pathItem = openapi_spec.paths[path]; | ||
| for (const method in pathItem) { | ||
| const operation = pathItem[method]; | ||
| if (operation.operationId) { | ||
| tools.push({ | ||
| id: operation.operationId, | ||
| name: operation.summary || operation.operationId, | ||
| description: operation.description || '', | ||
| icon: ApiIcon, | ||
| bgColor: '#6B7280', // Default color | ||
| type: operation.operationId, | ||
| server: serverName, | ||
| }); | ||
| } | ||
| } | ||
| } | ||
| 
     | 
||
| return tools; | ||
| } | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| // This file defines the MCP tool servers that will be available in the application. | ||
| 
     | 
||
| interface McpToolServer { | ||
| name: string | ||
| command: string[] | ||
| } | ||
| 
     | 
||
| export const mcpToolServers: McpToolServer[] = [ | ||
| { | ||
| name: 'Time Server', | ||
| command: ['uvx', 'mcp-server-time', '--local-timezone=America/New_York'], | ||
| }, | ||
| ] | ||
| 
         
      Comment on lines
    
      +8
     to 
      +13
    
   
  There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: Configuration structure mismatch: This uses   | 
||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| import { promises as fs } from 'fs'; | ||
| import path from 'path'; | ||
| 
     | 
||
| interface ToolServer { | ||
| name: string; | ||
| command: string; | ||
| args: string[]; | ||
| url: string; | ||
| } | ||
| 
     | 
||
| interface ToolServersConfig { | ||
| servers: ToolServer[]; | ||
| } | ||
| 
     | 
||
| interface McpoServerConfig { | ||
| [key: string]: { | ||
| command: string; | ||
| args: string[]; | ||
| url: string; | ||
| }; | ||
| } | ||
| 
         
      Comment on lines
    
      15
     to 
      21
    
   
  There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: Interface structure doesn't match existing   | 
||
| 
     | 
||
| interface McpoConfig { | ||
| mcpServers: McpoServerConfig; | ||
| } | ||
| 
     | 
||
| async function generateMcpoConfig() { | ||
| try { | ||
| const toolServersPath = path.resolve(process.cwd(), 'tool-servers.json'); | ||
| const toolServersContent = await fs.readFile(toolServersPath, 'utf-8'); | ||
| const toolServersConfig: ToolServersConfig = JSON.parse(toolServersContent); | ||
| 
     | 
||
| const mcpServers: McpoServerConfig = {}; | ||
| for (const server of toolServersConfig.servers) { | ||
| mcpServers[server.name] = { | ||
| command: server.command, | ||
| args: server.args, | ||
| url: server.url, | ||
| }; | ||
| } | ||
| 
     | 
||
| const mcpoConfig: McpoConfig = { | ||
| mcpServers, | ||
| }; | ||
| 
     | 
||
| const mcpoConfigPath = path.resolve(process.cwd(), 'mcpo-config.json'); | ||
| await fs.writeFile(mcpoConfigPath, JSON.stringify(mcpoConfig, null, 2)); | ||
| 
     | 
||
| console.log('Successfully generated mcpo-config.json'); | ||
| } catch (error) { | ||
| console.error('Error generating mcpo-config.json:', error); | ||
| process.exit(1); | ||
| } | ||
| } | ||
| 
     | 
||
| generateMcpoConfig(); | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| 
          
            
          
           | 
    @@ -91,5 +91,13 @@ services: | |
| timeout: 5s | ||
| retries: 5 | ||
| 
     | 
||
| mcpo: | ||
| image: openwebui/mcpo:latest | ||
| ports: | ||
| - '8000:8000' | ||
| volumes: | ||
| - ./mcpo-config.json:/app/config/config.json | ||
| command: ['uvx', 'mcpo', '--host', '0.0.0.0', '--port', '8000'] | ||
| 
         
      Comment on lines
    
      +94
     to 
      +100
    
   
  There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: Missing health check for the  
      Comment on lines
    
      +94
     to 
      +100
    
   
  There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. style: No restart policy specified for   | 
||
| 
     | 
||
| volumes: | ||
| postgres_data: | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| { | ||
| "mcpServers": { | ||
| "time": { | ||
| "command": "uvx", | ||
| "args": ["mcp-server-time", "--local-timezone=America/New_York"] | ||
| } | ||
| 
         
      Comment on lines
    
      +3
     to 
      +6
    
   
  There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. logic: Missing   | 
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| { | ||
| "servers": [ | ||
| { | ||
| "name": "time", | ||
| "command": "uvx", | ||
| "args": ["mcp-server-time", "--local-timezone=America/New_York"], | ||
| "url": "http://localhost:8001/openapi.json" | ||
| } | ||
| ] | ||
| } | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: MCP Tools section is not included in keyboard navigation system - users won't be able to navigate to these tools using arrow keys