Compare commits
1 Commits
fix/v2/inp
...
feat/mcp-u
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
22ed2b605e |
@@ -160,6 +160,7 @@
|
||||
"@langchain/community": "^1.0.0",
|
||||
"@langchain/core": "patch:@langchain/core@npm%3A1.0.2#~/.yarn/patches/@langchain-core-npm-1.0.2-183ef83fe4.patch",
|
||||
"@langchain/openai": "patch:@langchain/openai@npm%3A1.0.0#~/.yarn/patches/@langchain-openai-npm-1.0.0-474d0ad9d4.patch",
|
||||
"@mcp-ui/client": "^5.14.1",
|
||||
"@mistralai/mistralai": "^1.7.5",
|
||||
"@modelcontextprotocol/sdk": "^1.17.5",
|
||||
"@mozilla/readability": "^0.6.0",
|
||||
|
||||
@@ -8,6 +8,7 @@ import DiDiMcpServer from './didi-mcp'
|
||||
import DifyKnowledgeServer from './dify-knowledge'
|
||||
import FetchServer from './fetch'
|
||||
import FileSystemServer from './filesystem'
|
||||
import MCPUIDemoServer from './mcp-ui-demo'
|
||||
import MemoryServer from './memory'
|
||||
import PythonServer from './python'
|
||||
import ThinkingServer from './sequentialthinking'
|
||||
@@ -48,6 +49,9 @@ export function createInMemoryMCPServer(
|
||||
const apiKey = envs.DIDI_API_KEY
|
||||
return new DiDiMcpServer(apiKey).server
|
||||
}
|
||||
case BuiltinMCPServerNames.mcpUIDemo: {
|
||||
return new MCPUIDemoServer().server
|
||||
}
|
||||
default:
|
||||
throw new Error(`Unknown in-memory MCP server: ${name}`)
|
||||
}
|
||||
|
||||
433
src/main/mcpServers/mcp-ui-demo.ts
Normal file
433
src/main/mcpServers/mcp-ui-demo.ts
Normal file
@@ -0,0 +1,433 @@
|
||||
import { Server } from '@modelcontextprotocol/sdk/server/index.js'
|
||||
import { CallToolRequestSchema, ListToolsRequestSchema } from '@modelcontextprotocol/sdk/types.js'
|
||||
|
||||
const server = new Server(
|
||||
{
|
||||
name: 'mcp-ui-demo',
|
||||
version: '1.0.0'
|
||||
},
|
||||
{
|
||||
capabilities: {
|
||||
tools: {}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// HTML templates for different UIs
|
||||
const getHelloWorldUI = () =>
|
||||
`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body {
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
padding: 20px;
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
min-height: 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0;
|
||||
}
|
||||
.container {
|
||||
text-align: center;
|
||||
}
|
||||
h1 {
|
||||
font-size: 2.5em;
|
||||
margin-bottom: 10px;
|
||||
text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
|
||||
}
|
||||
p {
|
||||
font-size: 1.2em;
|
||||
opacity: 0.9;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>🎉 Hello from MCP UI!</h1>
|
||||
<p>This is a simple MCP UI Resource rendered in Cherry Studio</p>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`.trim()
|
||||
|
||||
const getInteractiveUI = () =>
|
||||
`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body {
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
padding: 20px;
|
||||
background: #f5f5f5;
|
||||
margin: 0;
|
||||
}
|
||||
.container {
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
h2 {
|
||||
color: #333;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
button {
|
||||
background: #667eea;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 12px 24px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
margin: 5px;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
button:hover {
|
||||
background: #5568d3;
|
||||
}
|
||||
#output {
|
||||
margin-top: 20px;
|
||||
padding: 15px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #e0e0e0;
|
||||
min-height: 50px;
|
||||
}
|
||||
.info {
|
||||
color: #666;
|
||||
font-size: 14px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h2>Interactive MCP UI Demo</h2>
|
||||
<p>Click the buttons to interact with MCP tools:</p>
|
||||
|
||||
<button onclick="callEchoTool()">Call Echo Tool</button>
|
||||
<button onclick="getTimestamp()">Get Timestamp</button>
|
||||
<button onclick="openLink()">Open External Link</button>
|
||||
|
||||
<div id="output"></div>
|
||||
|
||||
<div class="info">
|
||||
This UI can communicate with the host application through postMessage API.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function callEchoTool() {
|
||||
const output = document.getElementById('output');
|
||||
output.innerHTML = '<p style="color: #0066cc;">Calling echo tool...</p>';
|
||||
|
||||
window.parent.postMessage({
|
||||
type: 'tool',
|
||||
payload: {
|
||||
toolName: 'demo_echo',
|
||||
params: {
|
||||
message: 'Hello from MCP UI! Time: ' + new Date().toLocaleTimeString()
|
||||
}
|
||||
}
|
||||
}, '*');
|
||||
}
|
||||
|
||||
function getTimestamp() {
|
||||
const output = document.getElementById('output');
|
||||
const now = new Date();
|
||||
output.innerHTML = \`
|
||||
<p style="color: #00aa00;">
|
||||
<strong>Current Timestamp:</strong><br/>
|
||||
\${now.toLocaleString()}<br/>
|
||||
Unix: \${Math.floor(now.getTime() / 1000)}
|
||||
</p>
|
||||
\`;
|
||||
}
|
||||
|
||||
function openLink() {
|
||||
window.parent.postMessage({
|
||||
type: 'link',
|
||||
payload: {
|
||||
url: 'https://github.com/idosal/mcp-ui'
|
||||
}
|
||||
}, '*');
|
||||
}
|
||||
|
||||
// Listen for responses
|
||||
window.addEventListener('message', (event) => {
|
||||
if (event.data.type === 'ui-message-response') {
|
||||
const output = document.getElementById('output');
|
||||
const { response, error } = event.data.payload;
|
||||
|
||||
if (error) {
|
||||
output.innerHTML = \`<p style="color: #cc0000;">Error: \${error}</p>\`;
|
||||
} else {
|
||||
output.innerHTML = \`<p style="color: #00aa00;">Response: \${JSON.stringify(response, null, 2)}</p>\`;
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
`.trim()
|
||||
|
||||
const getFormUI = () =>
|
||||
`
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body {
|
||||
font-family: system-ui, -apple-system, sans-serif;
|
||||
padding: 20px;
|
||||
background: #f5f5f5;
|
||||
margin: 0;
|
||||
}
|
||||
.container {
|
||||
max-width: 500px;
|
||||
margin: 0 auto;
|
||||
background: white;
|
||||
padding: 30px;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
h2 {
|
||||
color: #333;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.form-group {
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
label {
|
||||
display: block;
|
||||
margin-bottom: 5px;
|
||||
color: #555;
|
||||
font-weight: 500;
|
||||
}
|
||||
input, textarea {
|
||||
width: 100%;
|
||||
padding: 10px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 6px;
|
||||
font-size: 14px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
textarea {
|
||||
min-height: 100px;
|
||||
resize: vertical;
|
||||
}
|
||||
button {
|
||||
background: #667eea;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 12px 24px;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
width: 100%;
|
||||
margin-top: 10px;
|
||||
}
|
||||
button:hover {
|
||||
background: #5568d3;
|
||||
}
|
||||
#result {
|
||||
margin-top: 20px;
|
||||
padding: 15px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 6px;
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h2>📝 Form UI Demo</h2>
|
||||
<form id="demoForm" onsubmit="handleSubmit(event)">
|
||||
<div class="form-group">
|
||||
<label for="name">Name:</label>
|
||||
<input type="text" id="name" name="name" required placeholder="Enter your name">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="email">Email:</label>
|
||||
<input type="email" id="email" name="email" required placeholder="your@email.com">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="message">Message:</label>
|
||||
<textarea id="message" name="message" required placeholder="Enter your message here..."></textarea>
|
||||
</div>
|
||||
|
||||
<button type="submit">Submit Form</button>
|
||||
</form>
|
||||
|
||||
<div id="result"></div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function handleSubmit(event) {
|
||||
event.preventDefault();
|
||||
|
||||
const formData = new FormData(event.target);
|
||||
const data = Object.fromEntries(formData.entries());
|
||||
|
||||
const result = document.getElementById('result');
|
||||
result.style.display = 'block';
|
||||
result.innerHTML = '<p style="color: #0066cc;">Submitting form...</p>';
|
||||
|
||||
// Send form data to host
|
||||
window.parent.postMessage({
|
||||
type: 'notify',
|
||||
payload: {
|
||||
message: 'Form submitted with data: ' + JSON.stringify(data)
|
||||
}
|
||||
}, '*');
|
||||
|
||||
// Display result
|
||||
result.innerHTML = \`
|
||||
<p style="color: #00aa00;"><strong>Form Submitted!</strong></p>
|
||||
<pre style="background: white; padding: 10px; border-radius: 4px; overflow-x: auto;">\${JSON.stringify(data, null, 2)}</pre>
|
||||
\`;
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
`.trim()
|
||||
|
||||
// List available tools
|
||||
server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
return {
|
||||
tools: [
|
||||
{
|
||||
name: 'demo_echo',
|
||||
description: 'Echo back the message sent from UI',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
message: {
|
||||
type: 'string',
|
||||
description: 'Message to echo back'
|
||||
}
|
||||
},
|
||||
required: ['message']
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'show_hello_ui',
|
||||
description: 'Display a simple hello world UI with gradient background',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'show_interactive_ui',
|
||||
description:
|
||||
'Display an interactive UI demo with buttons for calling tools, getting timestamps, and opening links',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {}
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'show_form_ui',
|
||||
description: 'Display a form UI demo with input fields for name, email, and message',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
})
|
||||
|
||||
// Handle tool calls
|
||||
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
const { name, arguments: args } = request.params
|
||||
|
||||
if (name === 'demo_echo') {
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: JSON.stringify({
|
||||
echo: args?.message || 'No message provided',
|
||||
timestamp: new Date().toISOString()
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
if (name === 'show_hello_ui') {
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: JSON.stringify({
|
||||
type: 'resource',
|
||||
resource: {
|
||||
uri: 'ui://demo/hello',
|
||||
mimeType: 'text/html',
|
||||
text: getHelloWorldUI()
|
||||
}
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
if (name === 'show_interactive_ui') {
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: JSON.stringify({
|
||||
type: 'resource',
|
||||
resource: {
|
||||
uri: 'ui://demo/interactive',
|
||||
mimeType: 'text/html',
|
||||
text: getInteractiveUI()
|
||||
}
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
if (name === 'show_form_ui') {
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: JSON.stringify({
|
||||
type: 'resource',
|
||||
resource: {
|
||||
uri: 'ui://demo/form',
|
||||
mimeType: 'text/html',
|
||||
text: getFormUI()
|
||||
}
|
||||
})
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`Unknown tool: ${name}`)
|
||||
})
|
||||
|
||||
class MCPUIDemoServer {
|
||||
public server: Server
|
||||
constructor() {
|
||||
this.server = server
|
||||
}
|
||||
}
|
||||
|
||||
export default MCPUIDemoServer
|
||||
157
src/renderer/src/components/MCPUIRenderer/MCPUIRenderer.tsx
Normal file
157
src/renderer/src/components/MCPUIRenderer/MCPUIRenderer.tsx
Normal file
@@ -0,0 +1,157 @@
|
||||
import { loggerService } from '@logger'
|
||||
import type { UIActionResult } from '@mcp-ui/client'
|
||||
import { UIResourceRenderer } from '@mcp-ui/client'
|
||||
import type { EmbeddedResource } from '@modelcontextprotocol/sdk/types.js'
|
||||
import { isUIResource } from '@renderer/types'
|
||||
import type { FC } from 'react'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
|
||||
const logger = loggerService.withContext('MCPUIRenderer')
|
||||
|
||||
interface Props {
|
||||
resource: EmbeddedResource
|
||||
serverId?: string
|
||||
serverName?: string
|
||||
onToolCall?: (toolName: string, params: any) => Promise<any>
|
||||
}
|
||||
|
||||
const MCPUIRenderer: FC<Props> = ({ resource, onToolCall }) => {
|
||||
const { t } = useTranslation()
|
||||
const [error] = useState<string | null>(null)
|
||||
|
||||
const handleUIAction = useCallback(
|
||||
async (result: UIActionResult): Promise<any> => {
|
||||
logger.debug('UI Action received:', result)
|
||||
|
||||
try {
|
||||
switch (result.type) {
|
||||
case 'tool': {
|
||||
// Handle tool call from UI
|
||||
if (onToolCall) {
|
||||
const { toolName, params } = result.payload
|
||||
logger.info(`UI requesting tool call: ${toolName}`, { params })
|
||||
const response = await onToolCall(toolName, params)
|
||||
|
||||
// Check if the response contains a UIResource
|
||||
try {
|
||||
if (response && response.content && Array.isArray(response.content)) {
|
||||
const firstContent = response.content[0]
|
||||
if (firstContent && firstContent.type === 'text' && firstContent.text) {
|
||||
const parsedText = JSON.parse(firstContent.text)
|
||||
if (isUIResource(parsedText)) {
|
||||
// Return the UIResource directly for rendering in the iframe
|
||||
logger.info('Tool response contains UIResource:', { uri: parsedText.resource.uri })
|
||||
return { status: 'success', data: parsedText }
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (parseError) {
|
||||
// Not a UIResource, return the original response
|
||||
logger.debug('Tool response is not a UIResource')
|
||||
}
|
||||
|
||||
return { status: 'success', data: response }
|
||||
} else {
|
||||
logger.warn('Tool call requested but no handler provided')
|
||||
return { status: 'error', message: 'Tool call handler not available' }
|
||||
}
|
||||
}
|
||||
|
||||
case 'intent': {
|
||||
// Handle user intent
|
||||
logger.info('UI intent:', result.payload)
|
||||
window.toast.info(t('message.mcp.ui.intent_received'))
|
||||
return { status: 'acknowledged' }
|
||||
}
|
||||
|
||||
case 'notify': {
|
||||
// Handle notification from UI
|
||||
logger.info('UI notification:', result.payload)
|
||||
window.toast.info(result.payload.message || t('message.mcp.ui.notification'))
|
||||
return { status: 'acknowledged' }
|
||||
}
|
||||
|
||||
case 'prompt': {
|
||||
// Handle prompt request from UI
|
||||
logger.info('UI prompt request:', result.payload)
|
||||
// TODO: Integrate with prompt system
|
||||
return { status: 'error', message: 'Prompt execution not yet implemented' }
|
||||
}
|
||||
|
||||
case 'link': {
|
||||
// Handle navigation request
|
||||
const { url } = result.payload
|
||||
logger.info('UI navigation request:', { url })
|
||||
window.open(url, '_blank')
|
||||
return { status: 'acknowledged' }
|
||||
}
|
||||
|
||||
default:
|
||||
logger.warn('Unknown UI action type:', { result })
|
||||
return { status: 'error', message: 'Unknown action type' }
|
||||
}
|
||||
} catch (err) {
|
||||
logger.error('Error handling UI action:', err as Error)
|
||||
return {
|
||||
status: 'error',
|
||||
message: err instanceof Error ? err.message : 'Unknown error'
|
||||
}
|
||||
}
|
||||
},
|
||||
[onToolCall, t]
|
||||
)
|
||||
|
||||
if (error) {
|
||||
return (
|
||||
<ErrorContainer>
|
||||
<ErrorTitle>{t('message.mcp.ui.error')}</ErrorTitle>
|
||||
<ErrorMessage>{error}</ErrorMessage>
|
||||
</ErrorContainer>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<UIContainer>
|
||||
<UIResourceRenderer resource={resource} onUIAction={handleUIAction} />
|
||||
</UIContainer>
|
||||
)
|
||||
}
|
||||
|
||||
const UIContainer = styled.div`
|
||||
width: 100%;
|
||||
min-height: 400px;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
background: var(--color-background);
|
||||
border: 1px solid var(--color-border);
|
||||
|
||||
iframe {
|
||||
width: 100%;
|
||||
border: none;
|
||||
min-height: 400px;
|
||||
height: 600px;
|
||||
}
|
||||
`
|
||||
|
||||
const ErrorContainer = styled.div`
|
||||
padding: 16px;
|
||||
border-radius: 8px;
|
||||
background: var(--color-error-bg, #fee);
|
||||
border: 1px solid var(--color-error-border, #fcc);
|
||||
color: var(--color-error-text, #c33);
|
||||
`
|
||||
|
||||
const ErrorTitle = styled.div`
|
||||
font-weight: 600;
|
||||
margin-bottom: 8px;
|
||||
font-size: 14px;
|
||||
`
|
||||
|
||||
const ErrorMessage = styled.div`
|
||||
font-size: 13px;
|
||||
opacity: 0.9;
|
||||
`
|
||||
|
||||
export default MCPUIRenderer
|
||||
1
src/renderer/src/components/MCPUIRenderer/index.ts
Normal file
1
src/renderer/src/components/MCPUIRenderer/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export { default as MCPUIRenderer } from './MCPUIRenderer'
|
||||
@@ -342,7 +342,8 @@ const builtInMcpDescriptionKeyMap: Record<BuiltinMCPServerName, string> = {
|
||||
[BuiltinMCPServerNames.filesystem]: 'settings.mcp.builtinServersDescriptions.filesystem',
|
||||
[BuiltinMCPServerNames.difyKnowledge]: 'settings.mcp.builtinServersDescriptions.dify_knowledge',
|
||||
[BuiltinMCPServerNames.python]: 'settings.mcp.builtinServersDescriptions.python',
|
||||
[BuiltinMCPServerNames.didiMCP]: 'settings.mcp.builtinServersDescriptions.didi_mcp'
|
||||
[BuiltinMCPServerNames.didiMCP]: 'settings.mcp.builtinServersDescriptions.didi_mcp',
|
||||
[BuiltinMCPServerNames.mcpUIDemo]: 'settings.mcp.builtinServersDescriptions.mcp_ui_demo'
|
||||
} as const
|
||||
|
||||
export const getBuiltInMcpServerDescriptionLabel = (key: string): string => {
|
||||
|
||||
@@ -1824,6 +1824,13 @@
|
||||
"preparing": "Preparing to export to Notion..."
|
||||
}
|
||||
},
|
||||
"mcp": {
|
||||
"ui": {
|
||||
"error": "UI Render Error",
|
||||
"intent_received": "Intent received from UI",
|
||||
"notification": "Notification from UI"
|
||||
}
|
||||
},
|
||||
"mention": {
|
||||
"title": "Switch model answer"
|
||||
},
|
||||
@@ -3851,6 +3858,7 @@
|
||||
"fetch": "MCP server for retrieving URL web content",
|
||||
"filesystem": "A Node.js server implementing the Model Context Protocol (MCP) for file system operations. Requires configuration of directories allowed for access.",
|
||||
"mcp_auto_install": "Automatically install MCP service (beta)",
|
||||
"mcp_ui_demo": "MCP UI Demo server with interactive UI resources showcase. Demonstrates HTML-based UI resources with buttons, forms, and tool call integration",
|
||||
"memory": "Persistent memory implementation based on a local knowledge graph. This enables the model to remember user-related information across different conversations. Requires configuring the MEMORY_FILE_PATH environment variable.",
|
||||
"no": "No description",
|
||||
"python": "Execute Python code in a secure sandbox environment. Run Python with Pyodide, supporting most standard libraries and scientific computing packages",
|
||||
|
||||
@@ -1824,6 +1824,13 @@
|
||||
"preparing": "正在准备导出到 Notion..."
|
||||
}
|
||||
},
|
||||
"mcp": {
|
||||
"ui": {
|
||||
"error": "[to be translated]:UI Render Error",
|
||||
"intent_received": "[to be translated]:Intent received from UI",
|
||||
"notification": "[to be translated]:Notification from UI"
|
||||
}
|
||||
},
|
||||
"mention": {
|
||||
"title": "切换模型回答"
|
||||
},
|
||||
@@ -3851,6 +3858,7 @@
|
||||
"fetch": "用于获取 URL 网页内容的 MCP 服务器",
|
||||
"filesystem": "实现文件系统操作的模型上下文协议(MCP)的 Node.js 服务器。需要配置允许访问的目录",
|
||||
"mcp_auto_install": "自动安装 MCP 服务(测试版)",
|
||||
"mcp_ui_demo": "[to be translated]:MCP UI Demo server with interactive UI resources showcase. Demonstrates HTML-based UI resources with buttons, forms, and tool call integration",
|
||||
"memory": "基于本地知识图谱的持久性记忆基础实现。这使得模型能够在不同对话间记住用户的相关信息。需要配置 MEMORY_FILE_PATH 环境变量。",
|
||||
"no": "无描述",
|
||||
"python": "在安全的沙盒环境中执行 Python 代码。使用 Pyodide 运行 Python,支持大多数标准库和科学计算包",
|
||||
|
||||
@@ -1824,6 +1824,13 @@
|
||||
"preparing": "正在準備匯出到 Notion..."
|
||||
}
|
||||
},
|
||||
"mcp": {
|
||||
"ui": {
|
||||
"error": "[to be translated]:UI Render Error",
|
||||
"intent_received": "[to be translated]:Intent received from UI",
|
||||
"notification": "[to be translated]:Notification from UI"
|
||||
}
|
||||
},
|
||||
"mention": {
|
||||
"title": "切換模型回答"
|
||||
},
|
||||
@@ -3851,6 +3858,7 @@
|
||||
"fetch": "用於獲取 URL 網頁內容的 MCP 伺服器",
|
||||
"filesystem": "實現文件系統操作的模型上下文協議(MCP)的 Node.js 伺服器。需要配置允許訪問的目錄",
|
||||
"mcp_auto_install": "自動安裝 MCP 服務(測試版)",
|
||||
"mcp_ui_demo": "[to be translated]:MCP UI Demo server with interactive UI resources showcase. Demonstrates HTML-based UI resources with buttons, forms, and tool call integration",
|
||||
"memory": "基於本地知識圖譜的持久性記憶基礎實現。這使得模型能夠在不同對話間記住使用者的相關資訊。需要配置 MEMORY_FILE_PATH 環境變數。",
|
||||
"no": "無描述",
|
||||
"python": "在安全的沙盒環境中執行 Python 代碼。使用 Pyodide 運行 Python,支援大多數標準庫和科學計算套件",
|
||||
|
||||
@@ -1824,6 +1824,13 @@
|
||||
"preparing": "Export nach Notion wird vorbereitet..."
|
||||
}
|
||||
},
|
||||
"mcp": {
|
||||
"ui": {
|
||||
"error": "[to be translated]:UI Render Error",
|
||||
"intent_received": "[to be translated]:Intent received from UI",
|
||||
"notification": "[to be translated]:Notification from UI"
|
||||
}
|
||||
},
|
||||
"mention": {
|
||||
"title": "Modellantwort wechseln"
|
||||
},
|
||||
@@ -3851,6 +3858,7 @@
|
||||
"fetch": "MCP-Server zum Abrufen von Webseiteninhalten",
|
||||
"filesystem": "MCP-Server für Dateisystemoperationen (Node.js), der den Zugriff auf bestimmte Verzeichnisse ermöglicht",
|
||||
"mcp_auto_install": "MCP-Service automatisch installieren (Beta-Version)",
|
||||
"mcp_ui_demo": "[to be translated]:MCP UI Demo server with interactive UI resources showcase. Demonstrates HTML-based UI resources with buttons, forms, and tool call integration",
|
||||
"memory": "MCP-Server mit persistenter Erinnerungsbasis auf lokalem Wissensgraphen, der Informationen über verschiedene Dialoge hinweg speichert. MEMORY_FILE_PATH-Umgebungsvariable muss konfiguriert werden",
|
||||
"no": "Keine Beschreibung",
|
||||
"python": "Python-Code in einem sicheren Sandbox-Umgebung ausführen. Verwendung von Pyodide für Python, Unterstützung für die meisten Standardbibliotheken und wissenschaftliche Pakete",
|
||||
|
||||
@@ -1824,6 +1824,13 @@
|
||||
"preparing": "Ετοιμάζεται η εξαγωγή στο Notion..."
|
||||
}
|
||||
},
|
||||
"mcp": {
|
||||
"ui": {
|
||||
"error": "[to be translated]:UI Render Error",
|
||||
"intent_received": "[to be translated]:Intent received from UI",
|
||||
"notification": "[to be translated]:Notification from UI"
|
||||
}
|
||||
},
|
||||
"mention": {
|
||||
"title": "Εναλλαγή απάντησης αστρόναυτη"
|
||||
},
|
||||
@@ -3851,6 +3858,7 @@
|
||||
"fetch": "Εξυπηρετητής MCP για λήψη περιεχομένου ιστοσελίδας URL",
|
||||
"filesystem": "Εξυπηρετητής Node.js για το πρωτόκολλο περιβάλλοντος μοντέλου (MCP) που εφαρμόζει λειτουργίες συστήματος αρχείων. Απαιτείται διαμόρφωση για την επιτροπή πρόσβασης σε καταλόγους",
|
||||
"mcp_auto_install": "Αυτόματη εγκατάσταση υπηρεσίας MCP (προβολή)",
|
||||
"mcp_ui_demo": "[to be translated]:MCP UI Demo server with interactive UI resources showcase. Demonstrates HTML-based UI resources with buttons, forms, and tool call integration",
|
||||
"memory": "Βασική υλοποίηση μόνιμης μνήμης με βάση τοπικό γράφημα γνώσης. Αυτό επιτρέπει στο μοντέλο να θυμάται πληροφορίες σχετικές με τον χρήστη ανάμεσα σε διαφορετικές συνομιλίες. Απαιτείται η ρύθμιση της μεταβλητής περιβάλλοντος MEMORY_FILE_PATH.",
|
||||
"no": "Χωρίς περιγραφή",
|
||||
"python": "Εκτελέστε κώδικα Python σε ένα ασφαλές περιβάλλον sandbox. Χρησιμοποιήστε το Pyodide για να εκτελέσετε Python, υποστηρίζοντας την πλειονότητα των βιβλιοθηκών της τυπικής βιβλιοθήκης και των πακέτων επιστημονικού υπολογισμού",
|
||||
|
||||
@@ -1824,6 +1824,13 @@
|
||||
"preparing": "Preparando para exportar a Notion..."
|
||||
}
|
||||
},
|
||||
"mcp": {
|
||||
"ui": {
|
||||
"error": "[to be translated]:UI Render Error",
|
||||
"intent_received": "[to be translated]:Intent received from UI",
|
||||
"notification": "[to be translated]:Notification from UI"
|
||||
}
|
||||
},
|
||||
"mention": {
|
||||
"title": "Cambiar modelo de respuesta"
|
||||
},
|
||||
@@ -3851,6 +3858,7 @@
|
||||
"fetch": "Servidor MCP para obtener el contenido de la página web de una URL",
|
||||
"filesystem": "Servidor Node.js que implementa el protocolo de contexto del modelo (MCP) para operaciones del sistema de archivos. Requiere configuración del directorio permitido para el acceso",
|
||||
"mcp_auto_install": "Instalación automática del servicio MCP (versión beta)",
|
||||
"mcp_ui_demo": "[to be translated]:MCP UI Demo server with interactive UI resources showcase. Demonstrates HTML-based UI resources with buttons, forms, and tool call integration",
|
||||
"memory": "Implementación básica de memoria persistente basada en un grafo de conocimiento local. Esto permite que el modelo recuerde información relevante del usuario entre diferentes conversaciones. Es necesario configurar la variable de entorno MEMORY_FILE_PATH.",
|
||||
"no": "sin descripción",
|
||||
"python": "Ejecuta código Python en un entorno sandbox seguro. Usa Pyodide para ejecutar Python, compatible con la mayoría de las bibliotecas estándar y paquetes de cálculo científico.",
|
||||
|
||||
@@ -1824,6 +1824,13 @@
|
||||
"preparing": "Préparation pour l'exportation vers Notion..."
|
||||
}
|
||||
},
|
||||
"mcp": {
|
||||
"ui": {
|
||||
"error": "[to be translated]:UI Render Error",
|
||||
"intent_received": "[to be translated]:Intent received from UI",
|
||||
"notification": "[to be translated]:Notification from UI"
|
||||
}
|
||||
},
|
||||
"mention": {
|
||||
"title": "Changer le modèle de réponse"
|
||||
},
|
||||
@@ -3851,6 +3858,7 @@
|
||||
"fetch": "serveur MCP utilisé pour récupérer le contenu des pages web URL",
|
||||
"filesystem": "Serveur Node.js implémentant le protocole de contexte de modèle (MCP) pour les opérations de système de fichiers. Nécessite une configuration des répertoires autorisés à être accédés.",
|
||||
"mcp_auto_install": "Installation automatique du service MCP (version bêta)",
|
||||
"mcp_ui_demo": "[to be translated]:MCP UI Demo server with interactive UI resources showcase. Demonstrates HTML-based UI resources with buttons, forms, and tool call integration",
|
||||
"memory": "Implémentation de base de mémoire persistante basée sur un graphe de connaissances local. Cela permet au modèle de se souvenir des informations relatives à l'utilisateur entre différentes conversations. Nécessite la configuration de la variable d'environnement MEMORY_FILE_PATH.",
|
||||
"no": "sans description",
|
||||
"python": "Exécutez du code Python dans un environnement bac à sable sécurisé. Utilisez Pyodide pour exécuter Python, prenant en charge la plupart des bibliothèques standard et des packages de calcul scientifique.",
|
||||
|
||||
@@ -1824,6 +1824,13 @@
|
||||
"preparing": "Notionへのエクスポートを準備中..."
|
||||
}
|
||||
},
|
||||
"mcp": {
|
||||
"ui": {
|
||||
"error": "[to be translated]:UI Render Error",
|
||||
"intent_received": "[to be translated]:Intent received from UI",
|
||||
"notification": "[to be translated]:Notification from UI"
|
||||
}
|
||||
},
|
||||
"mention": {
|
||||
"title": "モデルを切り替える"
|
||||
},
|
||||
@@ -3851,6 +3858,7 @@
|
||||
"fetch": "URLのウェブページコンテンツを取得するためのMCPサーバー",
|
||||
"filesystem": "Node.jsサーバーによるファイルシステム操作を実現するモデルコンテキストプロトコル(MCP)。アクセスを許可するディレクトリの設定が必要です",
|
||||
"mcp_auto_install": "MCPサービスの自動インストール(ベータ版)",
|
||||
"mcp_ui_demo": "[to be translated]:MCP UI Demo server with interactive UI resources showcase. Demonstrates HTML-based UI resources with buttons, forms, and tool call integration",
|
||||
"memory": "ローカルのナレッジグラフに基づく永続的なメモリの基本的な実装です。これにより、モデルは異なる会話間でユーザーの関連情報を記憶できるようになります。MEMORY_FILE_PATH 環境変数の設定が必要です。",
|
||||
"no": "説明なし",
|
||||
"python": "安全なサンドボックス環境でPythonコードを実行します。Pyodideを使用してPythonを実行し、ほとんどの標準ライブラリと科学計算パッケージをサポートしています。",
|
||||
|
||||
@@ -1824,6 +1824,13 @@
|
||||
"preparing": "Preparando exportação para Notion..."
|
||||
}
|
||||
},
|
||||
"mcp": {
|
||||
"ui": {
|
||||
"error": "[to be translated]:UI Render Error",
|
||||
"intent_received": "[to be translated]:Intent received from UI",
|
||||
"notification": "[to be translated]:Notification from UI"
|
||||
}
|
||||
},
|
||||
"mention": {
|
||||
"title": "Alternar modelo de resposta"
|
||||
},
|
||||
@@ -3851,6 +3858,7 @@
|
||||
"fetch": "servidor MCP para obter o conteúdo da página web do URL",
|
||||
"filesystem": "Servidor Node.js do protocolo de contexto de modelo (MCP) para implementar operações de sistema de ficheiros. Requer configuração do diretório permitido para acesso",
|
||||
"mcp_auto_install": "Instalação automática do serviço MCP (beta)",
|
||||
"mcp_ui_demo": "[to be translated]:MCP UI Demo server with interactive UI resources showcase. Demonstrates HTML-based UI resources with buttons, forms, and tool call integration",
|
||||
"memory": "Implementação base de memória persistente baseada em grafos de conhecimento locais. Isso permite que o modelo lembre informações relevantes do utilizador entre diferentes conversas. É necessário configurar a variável de ambiente MEMORY_FILE_PATH.",
|
||||
"no": "sem descrição",
|
||||
"python": "Executar código Python num ambiente sandbox seguro. Utilizar Pyodide para executar Python, suportando a maioria das bibliotecas padrão e pacotes de computação científica",
|
||||
|
||||
@@ -1824,6 +1824,13 @@
|
||||
"preparing": "Подготовка к экспорту в Notion..."
|
||||
}
|
||||
},
|
||||
"mcp": {
|
||||
"ui": {
|
||||
"error": "[to be translated]:UI Render Error",
|
||||
"intent_received": "[to be translated]:Intent received from UI",
|
||||
"notification": "[to be translated]:Notification from UI"
|
||||
}
|
||||
},
|
||||
"mention": {
|
||||
"title": "Переключить модель ответа"
|
||||
},
|
||||
@@ -3851,6 +3858,7 @@
|
||||
"fetch": "MCP-сервер для получения содержимого веб-страниц по URL",
|
||||
"filesystem": "Node.js-сервер протокола контекста модели (MCP) для реализации операций файловой системы. Требуется настройка каталогов, к которым разрешён доступ",
|
||||
"mcp_auto_install": "Автоматическая установка службы MCP (бета-версия)",
|
||||
"mcp_ui_demo": "[to be translated]:MCP UI Demo server with interactive UI resources showcase. Demonstrates HTML-based UI resources with buttons, forms, and tool call integration",
|
||||
"memory": "реализация постоянной памяти на основе локального графа знаний. Это позволяет модели запоминать информацию о пользователе между различными диалогами. Требуется настроить переменную среды MEMORY_FILE_PATH.",
|
||||
"no": "без описания",
|
||||
"python": "Выполняйте код Python в безопасной песочнице. Запускайте Python с помощью Pyodide, поддерживается большинство стандартных библиотек и пакетов для научных вычислений",
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { loggerService } from '@logger'
|
||||
import { CopyIcon, LoadingIcon } from '@renderer/components/Icons'
|
||||
import { MCPUIRenderer } from '@renderer/components/MCPUIRenderer'
|
||||
import { useCodeStyle } from '@renderer/context/CodeStyleProvider'
|
||||
import { useMCPServers } from '@renderer/hooks/useMCPServers'
|
||||
import { useSettings } from '@renderer/hooks/useSettings'
|
||||
import { useTimer } from '@renderer/hooks/useTimer'
|
||||
import type { MCPToolResponse } from '@renderer/types'
|
||||
import { isUIResource, type MCPToolResponse } from '@renderer/types'
|
||||
import type { ToolMessageBlock } from '@renderer/types/newMessage'
|
||||
import { isToolAutoApproved } from '@renderer/utils/mcp-tools'
|
||||
import { cancelToolAction, confirmToolAction } from '@renderer/utils/userConfirmation'
|
||||
@@ -342,26 +343,54 @@ const MessageMcpTool: FC<Props> = ({ block }) => {
|
||||
try {
|
||||
logger.debug(`renderPreview: ${content}`)
|
||||
const parsedResult = JSON.parse(content)
|
||||
switch (parsedResult.content[0]?.type) {
|
||||
|
||||
// Handle regular MCP tool responses
|
||||
const mcpResponse: any = parsedResult
|
||||
switch (mcpResponse.content?.[0]?.type) {
|
||||
case 'text':
|
||||
try {
|
||||
return (
|
||||
<CollapsedContent
|
||||
isExpanded={true}
|
||||
resultString={JSON.stringify(JSON.parse(parsedResult.content[0].text), null, 2)}
|
||||
/>
|
||||
)
|
||||
// Try to parse the text content to check if it's a UIResource
|
||||
const textContent = JSON.parse(mcpResponse.content[0].text)
|
||||
if (isUIResource(textContent)) {
|
||||
logger.info('Rendering UI Resource from MCP text response:', { uri: textContent.resource.uri })
|
||||
return (
|
||||
<MCPUIRenderer
|
||||
resource={textContent.resource}
|
||||
serverId={tool.serverId}
|
||||
serverName={tool.serverName}
|
||||
onToolCall={async (toolName, params) => {
|
||||
// Handle tool call from UI
|
||||
logger.info(`Tool call from UI: ${toolName}`, params)
|
||||
try {
|
||||
const server = mcpServers.find((s) => s.id === tool.serverId)
|
||||
if (!server) {
|
||||
throw new Error('Server not found')
|
||||
}
|
||||
const result = await window.api.mcp.callTool({
|
||||
server,
|
||||
name: toolName,
|
||||
args: params
|
||||
})
|
||||
return result
|
||||
} catch (error) {
|
||||
logger.error('Error calling tool from UI:', error as Error)
|
||||
throw error
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
// Regular JSON text content
|
||||
return <CollapsedContent isExpanded={true} resultString={JSON.stringify(textContent, null, 2)} />
|
||||
} catch (e) {
|
||||
// Not JSON or parsing failed, display as string
|
||||
return (
|
||||
<CollapsedContent
|
||||
isExpanded={true}
|
||||
resultString={JSON.stringify(parsedResult.content[0].text, null, 2)}
|
||||
/>
|
||||
<CollapsedContent isExpanded={true} resultString={JSON.stringify(mcpResponse.content[0].text, null, 2)} />
|
||||
)
|
||||
}
|
||||
|
||||
default:
|
||||
return <CollapsedContent isExpanded={true} resultString={JSON.stringify(parsedResult, null, 2)} />
|
||||
return <CollapsedContent isExpanded={true} resultString={JSON.stringify(mcpResponse, null, 2)} />
|
||||
}
|
||||
} catch (e) {
|
||||
logger.error('failed to render the preview of mcp results:', e as Error)
|
||||
|
||||
@@ -174,6 +174,16 @@ export const builtinMCPServers: BuiltinMCPServer[] = [
|
||||
provider: 'CherryAI',
|
||||
installSource: 'builtin',
|
||||
isTrusted: true
|
||||
},
|
||||
{
|
||||
id: nanoid(),
|
||||
name: BuiltinMCPServerNames.mcpUIDemo,
|
||||
type: 'inMemory',
|
||||
isActive: false,
|
||||
shouldConfig: true,
|
||||
provider: 'CherryAI',
|
||||
installSource: 'builtin',
|
||||
isTrusted: true
|
||||
}
|
||||
] as const
|
||||
|
||||
|
||||
@@ -731,7 +731,8 @@ export const BuiltinMCPServerNames = {
|
||||
filesystem: '@cherry/filesystem',
|
||||
difyKnowledge: '@cherry/dify-knowledge',
|
||||
python: '@cherry/python',
|
||||
didiMCP: '@cherry/didi-mcp'
|
||||
didiMCP: '@cherry/didi-mcp',
|
||||
mcpUIDemo: '@cherry/mcp-ui-demo'
|
||||
} as const
|
||||
|
||||
export type BuiltinMCPServerName = (typeof BuiltinMCPServerNames)[keyof typeof BuiltinMCPServerNames]
|
||||
@@ -841,6 +842,22 @@ export interface GetResourceResponse {
|
||||
contents: MCPResource[]
|
||||
}
|
||||
|
||||
// MCP UI Resource types
|
||||
export type UIResourceMimeType = 'text/html' | 'text/uri-list' | 'application/vnd.mcp-ui.remote-dom'
|
||||
|
||||
export interface UIResource {
|
||||
type: 'resource'
|
||||
resource: {
|
||||
uri: string // starts with 'ui://'
|
||||
mimeType: UIResourceMimeType
|
||||
text?: string
|
||||
blob?: string
|
||||
}
|
||||
}
|
||||
|
||||
// Re-export isUIResource from @mcp-ui/client
|
||||
export { isUIResource } from '@mcp-ui/client'
|
||||
|
||||
export interface QuickPhrase {
|
||||
id: string
|
||||
title: string
|
||||
|
||||
179
yarn.lock
179
yarn.lock
@@ -4657,6 +4657,22 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mcp-ui/client@npm:^5.14.1":
|
||||
version: 5.14.1
|
||||
resolution: "@mcp-ui/client@npm:5.14.1"
|
||||
dependencies:
|
||||
"@modelcontextprotocol/sdk": "npm:*"
|
||||
"@quilted/threads": "npm:^3.1.3"
|
||||
"@r2wc/react-to-web-component": "npm:^2.0.4"
|
||||
"@remote-dom/core": "npm:^1.8.0"
|
||||
"@remote-dom/react": "npm:^1.2.2"
|
||||
peerDependencies:
|
||||
react: ^18 || ^19
|
||||
react-dom: ^18 || ^19
|
||||
checksum: 10c0/8045c7ccb3e9333b53b23ed432b3b667d715bb90e799980865e03f65ccc8e566b09d93195825ffda3bcfb47ffa48db5464d981bcbbb8099b6101b865ebdbd55f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@mermaid-js/parser@npm:^0.6.2":
|
||||
version: 0.6.2
|
||||
resolution: "@mermaid-js/parser@npm:0.6.2"
|
||||
@@ -4684,6 +4700,32 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@modelcontextprotocol/sdk@npm:*":
|
||||
version: 1.22.0
|
||||
resolution: "@modelcontextprotocol/sdk@npm:1.22.0"
|
||||
dependencies:
|
||||
ajv: "npm:^8.17.1"
|
||||
ajv-formats: "npm:^3.0.1"
|
||||
content-type: "npm:^1.0.5"
|
||||
cors: "npm:^2.8.5"
|
||||
cross-spawn: "npm:^7.0.5"
|
||||
eventsource: "npm:^3.0.2"
|
||||
eventsource-parser: "npm:^3.0.0"
|
||||
express: "npm:^5.0.1"
|
||||
express-rate-limit: "npm:^7.5.0"
|
||||
pkce-challenge: "npm:^5.0.0"
|
||||
raw-body: "npm:^3.0.0"
|
||||
zod: "npm:^3.23.8"
|
||||
zod-to-json-schema: "npm:^3.24.1"
|
||||
peerDependencies:
|
||||
"@cfworker/json-schema": ^4.1.1
|
||||
peerDependenciesMeta:
|
||||
"@cfworker/json-schema":
|
||||
optional: true
|
||||
checksum: 10c0/71f4bef238715c248aa197ce820f95ac4fc75c7c311fc7d88c2e01d12692bffc5c9b9e3fe4c266ae0cca5df08c5b2fb6d60ab05d8905399665b67417d297903e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@modelcontextprotocol/sdk@npm:^1.17.5":
|
||||
version: 1.17.5
|
||||
resolution: "@modelcontextprotocol/sdk@npm:1.17.5"
|
||||
@@ -5392,6 +5434,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@preact/signals-core@npm:^1.8.0":
|
||||
version: 1.12.1
|
||||
resolution: "@preact/signals-core@npm:1.12.1"
|
||||
checksum: 10c0/06e73a9b6b90ef5967687eb64003cc7c1abae1950ade55941c3eefeca5d4f642010bce3f267f00663703d7f1509c51ced4751733b7ef5dcba29707fe38d375a1
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@protobufjs/aspromise@npm:^1.1.1, @protobufjs/aspromise@npm:^1.1.2":
|
||||
version: 1.1.2
|
||||
resolution: "@protobufjs/aspromise@npm:1.1.2"
|
||||
@@ -5474,6 +5523,48 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@quilted/events@npm:^2.1.3":
|
||||
version: 2.1.3
|
||||
resolution: "@quilted/events@npm:2.1.3"
|
||||
dependencies:
|
||||
"@preact/signals-core": "npm:^1.8.0"
|
||||
checksum: 10c0/7f0906c7f15d956f0e9aaa7e736c97b0a130e7cf651efb3b64ffc5868b352197d029acfd55787a36abf41064608421c5653de958b1490e6fb00948a942ee829d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@quilted/threads@npm:^3.1.3":
|
||||
version: 3.3.1
|
||||
resolution: "@quilted/threads@npm:3.3.1"
|
||||
dependencies:
|
||||
"@quilted/events": "npm:^2.1.3"
|
||||
peerDependencies:
|
||||
"@preact/signals-core": ^1.8.0
|
||||
peerDependenciesMeta:
|
||||
"@preact/signals-core":
|
||||
optional: true
|
||||
checksum: 10c0/ca9ed767aa65d5052c30f144a607c0f39721ab1cb91675b9fd0d05195605010ab182a50a946858b33d6c6d4f3947b3296245d6e05f9e4646d6f37bdc39175e70
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@r2wc/core@npm:^1.3.0":
|
||||
version: 1.3.0
|
||||
resolution: "@r2wc/core@npm:1.3.0"
|
||||
checksum: 10c0/cfa561f8f872c9f3337b963ca23ce0810157019c202a5144c4f45b8257ec348f1f3ccced4875f0ba633097663e3cfd8a1bd55d25b37cad76aeb526e8a596eacf
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@r2wc/react-to-web-component@npm:^2.0.4":
|
||||
version: 2.1.0
|
||||
resolution: "@r2wc/react-to-web-component@npm:2.1.0"
|
||||
dependencies:
|
||||
"@r2wc/core": "npm:^1.3.0"
|
||||
peerDependencies:
|
||||
react: ^18.0.0 || ^19.0.0
|
||||
react-dom: ^18.0.0 || ^19.0.0
|
||||
checksum: 10c0/04fd1f45afd8ffa0567763abf5aa67c0d1b09be75f36390b90e6b4cd6e5e1a80c6793387868f9df600998367c86caee55dd9a8ed0c73be9d662e2925de2c0faf
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@radix-ui/primitive@npm:1.1.3":
|
||||
version: 1.1.3
|
||||
resolution: "@radix-ui/primitive@npm:1.1.3"
|
||||
@@ -6103,6 +6194,46 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@remote-dom/core@npm:^1.7.0, @remote-dom/core@npm:^1.8.0":
|
||||
version: 1.10.1
|
||||
resolution: "@remote-dom/core@npm:1.10.1"
|
||||
dependencies:
|
||||
"@remote-dom/polyfill": "npm:^1.5.1"
|
||||
htm: "npm:^3.1.1"
|
||||
peerDependencies:
|
||||
"@preact/signals-core": ^1.3.0
|
||||
peerDependenciesMeta:
|
||||
"@preact/signals-core":
|
||||
optional: true
|
||||
preact:
|
||||
optional: true
|
||||
checksum: 10c0/53db62196471f8201665accfad2bc1ca8db4b305d2485bdd57cd700975e93d1ce02f0abf95a90ad1d36dd8c06ff91e81e153bb9dd2ab487a5e7a6f827b3b8145
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@remote-dom/polyfill@npm:^1.5.1":
|
||||
version: 1.5.1
|
||||
resolution: "@remote-dom/polyfill@npm:1.5.1"
|
||||
checksum: 10c0/753836a286214e9ac8d6246501d4d7824fe600ae4b49c3fe6ac5467934b5a15aeb0f80e773f7c7219f829ac5758be077468ede6da9a5de14260f3627ffcd6e1f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@remote-dom/react@npm:^1.2.2":
|
||||
version: 1.2.2
|
||||
resolution: "@remote-dom/react@npm:1.2.2"
|
||||
dependencies:
|
||||
"@remote-dom/core": "npm:^1.7.0"
|
||||
"@types/react": "npm:^18.0.0"
|
||||
htm: "npm:^3.1.1"
|
||||
peerDependencies:
|
||||
react: ^17.0.0 || ^18.0.0
|
||||
peerDependenciesMeta:
|
||||
react:
|
||||
optional: true
|
||||
checksum: 10c0/87883e06dab4a2a52cf9aa6f397166a25054aebf0a9f401bfb67831038dac59fb549754054a297617ba7ca8f33c8967765570fed3cf27a280d921d8f73d2dd64
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@replit/codemirror-lang-nix@npm:^6.0.1":
|
||||
version: 6.0.1
|
||||
resolution: "@replit/codemirror-lang-nix@npm:6.0.1"
|
||||
@@ -8749,6 +8880,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/prop-types@npm:*":
|
||||
version: 15.7.15
|
||||
resolution: "@types/prop-types@npm:15.7.15"
|
||||
checksum: 10c0/b59aad1ad19bf1733cf524fd4e618196c6c7690f48ee70a327eb450a42aab8e8a063fbe59ca0a5701aebe2d92d582292c0fb845ea57474f6a15f6994b0e260b2
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/qs@npm:*":
|
||||
version: 6.14.0
|
||||
resolution: "@types/qs@npm:6.14.0"
|
||||
@@ -8808,6 +8946,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/react@npm:^18.0.0":
|
||||
version: 18.3.27
|
||||
resolution: "@types/react@npm:18.3.27"
|
||||
dependencies:
|
||||
"@types/prop-types": "npm:*"
|
||||
csstype: "npm:^3.2.2"
|
||||
checksum: 10c0/a761d2f58de03d0714806cc65d32bb3d73fb33a08dd030d255b47a295e5fff2a775cf1c20b786824d8deb6454eaccce9bc6998d9899c14fc04bbd1b0b0b72897
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/react@npm:^19.0.12":
|
||||
version: 19.1.2
|
||||
resolution: "@types/react@npm:19.1.2"
|
||||
@@ -9982,6 +10130,7 @@ __metadata:
|
||||
"@langchain/openai": "patch:@langchain/openai@npm%3A1.0.0#~/.yarn/patches/@langchain-openai-npm-1.0.0-474d0ad9d4.patch"
|
||||
"@libsql/client": "npm:0.14.0"
|
||||
"@libsql/win32-x64-msvc": "npm:^0.4.7"
|
||||
"@mcp-ui/client": "npm:^5.14.1"
|
||||
"@mistralai/mistralai": "npm:^1.7.5"
|
||||
"@modelcontextprotocol/sdk": "npm:^1.17.5"
|
||||
"@mozilla/readability": "npm:^0.6.0"
|
||||
@@ -10341,6 +10490,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ajv-formats@npm:^3.0.1":
|
||||
version: 3.0.1
|
||||
resolution: "ajv-formats@npm:3.0.1"
|
||||
dependencies:
|
||||
ajv: "npm:^8.0.0"
|
||||
peerDependencies:
|
||||
ajv: ^8.0.0
|
||||
peerDependenciesMeta:
|
||||
ajv:
|
||||
optional: true
|
||||
checksum: 10c0/168d6bca1ea9f163b41c8147bae537e67bd963357a5488a1eaf3abe8baa8eec806d4e45f15b10767e6020679315c7e1e5e6803088dfb84efa2b4e9353b83dd0a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ajv-keywords@npm:^3.4.1":
|
||||
version: 3.5.2
|
||||
resolution: "ajv-keywords@npm:3.5.2"
|
||||
@@ -10362,7 +10525,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ajv@npm:^8.0.0, ajv@npm:^8.6.3":
|
||||
"ajv@npm:^8.0.0, ajv@npm:^8.17.1, ajv@npm:^8.6.3":
|
||||
version: 8.17.1
|
||||
resolution: "ajv@npm:8.17.1"
|
||||
dependencies:
|
||||
@@ -12325,6 +12488,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"csstype@npm:^3.2.2":
|
||||
version: 3.2.3
|
||||
resolution: "csstype@npm:3.2.3"
|
||||
checksum: 10c0/cd29c51e70fa822f1cecd8641a1445bed7063697469d35633b516e60fe8c1bde04b08f6c5b6022136bb669b64c63d4173af54864510fbb4ee23281801841a3ce
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"csv-parse@npm:^5.6.0":
|
||||
version: 5.6.0
|
||||
resolution: "csv-parse@npm:5.6.0"
|
||||
@@ -16017,6 +16187,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"htm@npm:^3.1.1":
|
||||
version: 3.1.1
|
||||
resolution: "htm@npm:3.1.1"
|
||||
checksum: 10c0/0de4c8fff2b8e76c162235ae80dbf93ca5eef1575bd50596a06ce9bebf1a6da5efc467417c53034a9ffa2ab9ecff819cbec041dc9087894b2b900ad4de26c7e7
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"html-encoding-sniffer@npm:^4.0.0":
|
||||
version: 4.0.0
|
||||
resolution: "html-encoding-sniffer@npm:4.0.0"
|
||||
|
||||
Reference in New Issue
Block a user