Skip to content

Conversation

@kagol
Copy link
Member

@kagol kagol commented Dec 31, 2025

PR

主要更新:

  • 引入 @opentiny/next-sdk / @opentiny/next-remoter,并接入 WebAgent 服务,用于实现智能化,可通过自然语言,让AI帮助人完成添加词条、添加菜单等操作
  • 增加 MCP 工具:添加词条(add-i18n-entry)、添加菜单(add-menu

效果如下:

添加词条:

AI添加词条

添加菜单:

AI添加菜单

PR Checklist

Please check if your PR fulfills the following requirements:

  • The commit message follows our Commit Message Guidelines
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • Other... Please describe:

What is the current behavior?

Issue Number: N/A

What is the new behavior?

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

Summary by CodeRabbit

  • New Features

    • Introduced remote agent functionality with TinyRemoter component integration
    • Added MCP server capabilities for automated locale and menu management operations
    • Enhanced menu management with remote command interface support
  • Bug Fixes

    • Corrected CSS syntax and improved layout styling
  • Chores

    • Added new dependencies for remote agent and SDK functionality

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Dec 31, 2025

Walkthrough

This change integrates the Model Context Protocol (MCP) framework into a TinyVue template by adding MCP dependencies, establishing a client-server transport mechanism in the main App component, and registering MCP server tools in specific feature components (locale and menu management) to enable remote command execution.

Changes

Cohort / File(s) Summary
Dependency Management
package.json, template/tinyvue/package.json
Added pnpm override pinning @modelcontextprotocol/sdk to 1.16.0; added runtime dependencies @opentiny/next-remoter (^0.0.10) and @opentiny/next-sdk (^0.1.15) to TinyVue template
Core MCP Infrastructure
template/tinyvue/src/App.vue
Initialized MCP client-server transport pair in root component; creates WebMcpClient connection with session-based routing via createMessageChannelPairTransport and provides serverTransport to child components
Utility & Styling
template/tinyvue/src/utils/base-utils.ts, template/tinyvue/src/assets/style/global.less
Added sleep() helper function for async delays; fixed missing CSS closing brace and added z-index: 999 for tr-container
MCP Server Tool Registration
template/tinyvue/src/views/locale/components/add-locale.vue, template/tinyvue/src/views/menu/info/components/add-menu.vue, template/tinyvue/src/views/menu/info/components/info-tab.vue
Registered MCP server tools ("add-i18n-entry" and "add-menu") with input schemas; wired server lifecycle to component initialization; added public setMenuInfo() method for programmatic form population

Sequence Diagram(s)

sequenceDiagram
    actor Client
    participant App as App.vue
    participant Transport as Message Channel<br/>Transport
    participant MCP as WebMcpClient
    participant Tools as Tool Components<br/>(locale, menu)
    participant Server as WebMcpServer<br/>per Component

    Client->>App: Mount
    App->>Transport: createMessageChannelPairTransport()
    App->>MCP: new WebMcpClient(clientTransport)
    App->>MCP: client.connect({agent: true, sessionId, url})
    MCP-->>App: return sessionId
    App->>+Tools: provide(serverTransport)
    
    Tools->>Server: onMounted() creates WebMcpServer
    Tools->>Server: registerTool("add-menu" | "add-i18n-entry", inputSchema, handler)
    Tools->>Server: server.connect(serverTransport)
    deactivate Tools
    
    rect rgba(200, 220, 255, 0.3)
        note over Client,Server: MCP Tool Execution Flow
        Client->>MCP: Call remote tool
        MCP->>Transport: Send command
        Transport->>Server: Route to server
        Server->>Server: Execute tool handler
        Server-->>Transport: Return result
        Transport-->>MCP: Receive result
        MCP-->>Client: Tool response
    end
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Poem

🐰 With hops and bounds, we integrate,
Model Context Protocol made great!
Tools spring forth from component nodes,
Messages dance on transport roads,
A remoter dream takes rabbit shape. ✨

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The PR title 'feat: add @opentiny/next-sdk' accurately summarizes the main change, which is integrating the new @opentiny/next-sdk package along with related AI-assisted operations and MCP tools.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch kagol/add-opentiny-next-sdk

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added the enhancement New feature or request label Dec 31, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🧹 Nitpick comments (5)
template/tinyvue/src/assets/style/global.less (1)

43-45: Consider whether !important is necessary.

The high z-index with !important ensures .tr-container appears on top, which is appropriate for overlays or agent UI components. However, !important can make future CSS adjustments more difficult. If the specificity can be managed through other means (e.g., more specific selectors or stacking context), that would be more maintainable.

template/tinyvue/src/utils/base-utils.ts (1)

12-14: LGTM! Simple and effective delay utility.

The sleep utility is correctly implemented and will be useful for orchestrating asynchronous MCP workflows. The function is imported and used in template/tinyvue/src/views/locale/components/add-locale.vue and template/tinyvue/src/views/menu/info/components/info-tab.vue.

Note: Consider adding a semicolon at the end of line 13 for consistency with the file's style (line 9 has a semicolon).

Optional: Add semicolon for consistency
 export const sleep = (ms: number): Promise<void> => {
-  return new Promise((resolve) => setTimeout(resolve, ms))
+  return new Promise((resolve) => setTimeout(resolve, ms));
 }
template/tinyvue/src/views/menu/info/components/add-menu.vue (1)

174-183: Consider simplifying property assignment.

The new setMenuInfo method assigns data fields to the reactive menuInfo object. The current implementation works correctly but is verbose. Consider using Object.assign for a more concise approach.

Simplified implementation
 setMenuInfo: (data: Omit<CreateMenuDto, 'id'>) => {
-  menuInfo.name = data.name;
-  menuInfo.path = data.path;
-  menuInfo.component = data.component;
-  menuInfo.icon = data.icon;
-  menuInfo.menuType = data.menuType;
-  menuInfo.parentId = data.parentId;
-  menuInfo.order = data.order;
-  menuInfo.locale = data.locale;
+  Object.assign(menuInfo, data);
 },
template/tinyvue/src/views/locale/components/add-locale.vue (1)

237-237: Consider using an enum for language IDs.

Line 237 defines the language ID as a union of literals (z.literal(1) and z.literal(2)). While functional, this approach makes the code less maintainable. Consider defining a language enum to improve readability and type safety.

Enum-based approach
// Add at the top of the file or in a shared types file
enum LanguageId {
  EN_US = 1,
  ZH_CN = 2
}

// Then use in schema:
lang: z.nativeEnum(LanguageId).describe('词条语言ID,英文 enUS 为:1,中文 zhCN 为:2'),

This makes the intent clearer and provides better IntelliSense support.

package.json (1)

34-38: Consider upgrading to the latest @modelcontextprotocol/sdk version or document the pinning rationale.

Version 1.16.0 exists on npm with no reported direct security vulnerabilities. However, it is significantly outdated—the latest stable release is 1.25.0 (Dec 15, 2025). If this older version is intentionally pinned for compatibility or other reasons, add a comment explaining the constraint. Additionally, run npm audit to check for vulnerabilities in transitive dependencies.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 12f464b and 521b9e7.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (8)
  • package.json
  • template/tinyvue/package.json
  • template/tinyvue/src/App.vue
  • template/tinyvue/src/assets/style/global.less
  • template/tinyvue/src/utils/base-utils.ts
  • template/tinyvue/src/views/locale/components/add-locale.vue
  • template/tinyvue/src/views/menu/info/components/add-menu.vue
  • template/tinyvue/src/views/menu/info/components/info-tab.vue
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: e2e-test
🔇 Additional comments (2)
template/tinyvue/src/assets/style/global.less (1)

41-41: LGTM! Syntax fix applied correctly.

The missing closing brace for the .tiny-button block has been properly added.

template/tinyvue/src/App.vue (1)

9-26: LGTM! TinyRemoter configured appropriately.

The TinyRemoter component is properly configured with the agent root URL and menu item visibility controls. The reactive sessionId binding will enable dynamic session tracking.

Comment on lines +56 to +74
onMounted(async () => {
const [serverTransport, clientTransport] = createMessageChannelPairTransport()
provide('serverTransport', serverTransport)
// 创建 WebMcpClient ,并与 WebAgent 连接
const client = new WebMcpClient()
await client.connect(clientTransport)
const { sessionId: sessionID } = await client.connect({
agent: true,
// sessionId 为可选参数。若传入该参数,系统将使用指定值作为会话标识;若未传入,WebAgent 服务将自动生成一个随机的字符串作为 sessionId。为便于通过 MCP Inspector 工具进行调试,此处采用了固定的 sessionId。用户亦可通过浏览器原生提供的 crypto.randomUUID() 方法生成随机字符串作为会话标识。
sessionId: 'd299a869-c674-4125-a84b-bb4e24079b99',
url: 'https://agent.opentiny.design/api/v1/webmcp-trial/mcp' // http://localhost:3005/api/v1/webmcp/mcp
})
sessionId.value = sessionID
console.log('sessionId:', sessionId.value)
})
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add error handling and reconsider hard-coded sessionId.

The MCP client initialization has two concerns:

  1. Hard-coded sessionId on line 68 defeats the purpose of session management. The comment suggests this is for debugging with MCP Inspector, but production code should use dynamic session IDs. Consider using crypto.randomUUID() or making the fixed ID conditional based on an environment variable.

  2. Missing error handling: The async operations in onMounted lack try-catch blocks. If client.connect() fails, the error will be unhandled and sessionId.value will remain empty, potentially breaking the TinyRemoter integration.

Proposed fix with error handling and environment-based sessionId
 const sessionId = ref('')
 onMounted(async () => {
-  const [serverTransport, clientTransport] = createMessageChannelPairTransport()
-
-  provide('serverTransport', serverTransport)
-
-  // 创建 WebMcpClient ,并与 WebAgent 连接
-  const client = new WebMcpClient()
-  await client.connect(clientTransport)
-  const { sessionId: sessionID } = await client.connect({
-    agent: true,
-
-    // sessionId 为可选参数。若传入该参数,系统将使用指定值作为会话标识;若未传入,WebAgent 服务将自动生成一个随机的字符串作为 sessionId。为便于通过 MCP Inspector 工具进行调试,此处采用了固定的 sessionId。用户亦可通过浏览器原生提供的 crypto.randomUUID() 方法生成随机字符串作为会话标识。
-    sessionId: 'd299a869-c674-4125-a84b-bb4e24079b99',
-
-    url: 'https://agent.opentiny.design/api/v1/webmcp-trial/mcp' // http://localhost:3005/api/v1/webmcp/mcp
-  })
-  sessionId.value = sessionID
-  console.log('sessionId:', sessionId.value)
+  try {
+    const [serverTransport, clientTransport] = createMessageChannelPairTransport()
+    
+    provide('serverTransport', serverTransport)
+    
+    const client = new WebMcpClient()
+    await client.connect(clientTransport)
+    
+    // Use fixed sessionId only in development for debugging
+    const fixedSessionId = import.meta.env.DEV 
+      ? 'd299a869-c674-4125-a84b-bb4e24079b99'
+      : crypto.randomUUID()
+    
+    const { sessionId: sessionID } = await client.connect({
+      agent: true,
+      sessionId: fixedSessionId,
+      url: 'https://agent.opentiny.design/api/v1/webmcp-trial/mcp'
+    })
+    sessionId.value = sessionID
+    console.log('sessionId:', sessionId.value)
+  } catch (error) {
+    console.error('Failed to initialize MCP client:', error)
+    // Consider notifying the user or disabling MCP features
+  }
 })
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onMounted(async () => {
const [serverTransport, clientTransport] = createMessageChannelPairTransport()
provide('serverTransport', serverTransport)
// 创建 WebMcpClient ,并与 WebAgent 连接
const client = new WebMcpClient()
await client.connect(clientTransport)
const { sessionId: sessionID } = await client.connect({
agent: true,
// sessionId 为可选参数。若传入该参数,系统将使用指定值作为会话标识;若未传入,WebAgent 服务将自动生成一个随机的字符串作为 sessionId。为便于通过 MCP Inspector 工具进行调试,此处采用了固定的 sessionId。用户亦可通过浏览器原生提供的 crypto.randomUUID() 方法生成随机字符串作为会话标识。
sessionId: 'd299a869-c674-4125-a84b-bb4e24079b99',
url: 'https://agent.opentiny.design/api/v1/webmcp-trial/mcp' // http://localhost:3005/api/v1/webmcp/mcp
})
sessionId.value = sessionID
console.log('sessionId:', sessionId.value)
})
onMounted(async () => {
try {
const [serverTransport, clientTransport] = createMessageChannelPairTransport()
provide('serverTransport', serverTransport)
const client = new WebMcpClient()
await client.connect(clientTransport)
// Use fixed sessionId only in development for debugging
const fixedSessionId = import.meta.env.DEV
? 'd299a869-c674-4125-a84b-bb4e24079b99'
: crypto.randomUUID()
const { sessionId: sessionID } = await client.connect({
agent: true,
sessionId: fixedSessionId,
url: 'https://agent.opentiny.design/api/v1/webmcp-trial/mcp'
})
sessionId.value = sessionID
console.log('sessionId:', sessionId.value)
} catch (error) {
console.error('Failed to initialize MCP client:', error)
// Consider notifying the user or disabling MCP features
}
})
🤖 Prompt for AI Agents
In template/tinyvue/src/App.vue around lines 56 to 74, the onMounted block both
hard-codes a sessionId and lacks error handling; wrap the async client
creation/connect calls in a try-catch, log or surface errors, and ensure the
UI/state is updated only on success (e.g., set sessionId.value inside the try
and set an error state in the catch). Replace the fixed sessionId with a dynamic
value by default (use crypto.randomUUID()) and make the fixed ID conditional
(e.g., only use the hard-coded value when a debug flag or environment variable
is present) so production uses a generated UUID.

Comment on lines +222 to +253
onMounted(async () => {
const server = new WebMcpServer({
name: 'i18n-management-mcp-server',
version: '1.0.0'
})
const serverTransport = inject<any>('serverTransport')
server.registerTool(
'add-i18n-entry',
{
title: '添加国际化词条',
description: '添加国际化词条',
inputSchema: {
key: z.string().describe('词条关键字'),
content: z.string().describe('词条内容'),
lang: z.union([z.literal(1), z.literal(2)]).describe('词条语言ID,英文 enUS 为:1,中文 zhCN 为:2'),
}
},
async ({ key, content, lang }) => {
onOpen()
await sleep(1000)
locale.key = key
locale.content = content
locale.lang = lang
await sleep(1000)
addLocale()
return { content: [{ type: 'text', text: `收到: ${key}` }] }
}
)
await server.connect(serverTransport)
});
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Check if Transport type is exported from @opentiny/next-sdk
rg -nP "export.*Transport" node_modules/@opentiny/next-sdk -A 2

Repository: opentiny/tiny-pro

Length of output: 132


🏁 Script executed:

# Also check the actual file to verify it exists and code matches
if [ -f "template/tinyvue/src/views/locale/components/add-locale.vue" ]; then
  echo "=== File exists. Checking lines 222-253 ==="
  sed -n '222,253p' "template/tinyvue/src/views/locale/components/add-locale.vue"
else
  echo "File not found at template/tinyvue/src/views/locale/components/add-locale.vue"
  # Try to find it
  find . -name "add-locale.vue" -type f 2>/dev/null
fi

Repository: opentiny/tiny-pro

Length of output: 994


🏁 Script executed:

# Check if info-tab.vue exists and has similar MCP server setup pattern
find . -name "info-tab.vue" -type f 2>/dev/null | head -5

Repository: opentiny/tiny-pro

Length of output: 388


🏁 Script executed:

# Check if @opentiny/next-sdk is in package.json
cat package.json | grep -A 5 -B 5 "@opentiny/next-sdk"

Repository: opentiny/tiny-pro

Length of output: 43


🏁 Script executed:

# Check one info-tab.vue file to see similar MCP server pattern
head -n 400 "./template/tinyvue/src/views/menu/info/components/info-tab.vue" | grep -A 50 "onMounted"

Repository: opentiny/tiny-pro

Length of output: 3091


🏁 Script executed:

# Check package.json file itself for @opentiny/next-sdk and dependencies section
head -n 100 package.json | tail -n 50

Repository: opentiny/tiny-pro

Length of output: 2327


🏁 Script executed:

# Search for Transport type usage in the codebase
rg "Transport" --type vue --type ts --type js | head -20

Repository: opentiny/tiny-pro

Length of output: 88


🏁 Script executed:

# Search for Transport type usage more broadly
rg "Transport" --type ts --type js | head -20

Repository: opentiny/tiny-pro

Length of output: 880


🏁 Script executed:

# Check full package.json dependencies for @opentiny/next-sdk and related packages
rg "@opentiny" package.json

Repository: opentiny/tiny-pro

Length of output: 172


🏁 Script executed:

# Look for WebMcpServer import to understand where Transport might come from
rg "WebMcpServer|import.*Transport" -A 2 -B 2 | head -30

Repository: opentiny/tiny-pro

Length of output: 2406


🏁 Script executed:

# Check App.vue to see how serverTransport is typed and used
rg -A 10 "createMessageChannelPairTransport" "template/tinyvue/src/App.vue"

Repository: opentiny/tiny-pro

Length of output: 991


🏁 Script executed:

# Look for type definitions or interfaces related to Transport in the codebase
rg "type.*Transport|interface.*Transport" --type ts -A 3

Repository: opentiny/tiny-pro

Length of output: 43


🏁 Script executed:

# Check if there's a type definition file or declaration in node_modules or src
find . -name "*.d.ts" -o -name "*.ts" | xargs grep -l "Transport" 2>/dev/null | head -10

Repository: opentiny/tiny-pro

Length of output: 43


Add error handling and improve type safety.

The MCP server setup mirrors the pattern in info-tab.vue and has similar concerns:

  1. Type safety: Line 227 uses any for serverTransport. This should use a proper type instead of any.

  2. Hard-coded delays: Lines 242 and 246 use fixed 1000ms delays. Extract these as named constants.

  3. Missing error handling: No try-catch blocks around async operations. Both the tool handler (lines 240-248) and server connection (line 252) should handle potential errors.

  4. UI orchestration: The tool handler directly calls onOpen() and addLocale(), tightly coupling MCP logic to UI implementation.

These same issues appear in info-tab.vue (menu-management-mcp-server setup).

Proposed improvements
+const MCP_UI_DELAY = 1000; // ms
+
 onMounted(async () => {
+  try {
     const server = new WebMcpServer({
       name: 'i18n-management-mcp-server',
       version: '1.0.0'
     })
-    const serverTransport = inject<any>('serverTransport')
+    const serverTransport = inject('serverTransport')
+    if (!serverTransport) {
+      console.error('serverTransport not provided')
+      return
+    }

     server.registerTool(
       'add-i18n-entry',
       {
         title: '添加国际化词条',
         description: '添加国际化词条',
         inputSchema: {
           key: z.string().describe('词条关键字'),
           content: z.string().describe('词条内容'),
           lang: z.union([z.literal(1), z.literal(2)]).describe('词条语言ID,英文 enUS 为:1,中文 zhCN 为:2'),
         }
       },
       async ({ key, content, lang }) => {
+        try {
           onOpen()
-          await sleep(1000)
+          await sleep(MCP_UI_DELAY)
           locale.key = key
           locale.content = content
           locale.lang = lang
-          await sleep(1000)
+          await sleep(MCP_UI_DELAY)
           addLocale()
           return { content: [{ type: 'text', text: `收到: ${key}` }] }
+        } catch (error) {
+          console.error('Failed to add i18n entry via MCP:', error)
+          return { 
+            content: [{ 
+              type: 'text', 
+              text: `添加词条失败: ${error instanceof Error ? error.message : String(error)}` 
+            }],
+            isError: true
+          }
+        }
       }
     )

     await server.connect(serverTransport)
+    console.log('i18n MCP server connected successfully')
+  } catch (error) {
+    console.error('Failed to initialize i18n MCP server:', error)
+  }
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onMounted(async () => {
const server = new WebMcpServer({
name: 'i18n-management-mcp-server',
version: '1.0.0'
})
const serverTransport = inject<any>('serverTransport')
server.registerTool(
'add-i18n-entry',
{
title: '添加国际化词条',
description: '添加国际化词条',
inputSchema: {
key: z.string().describe('词条关键字'),
content: z.string().describe('词条内容'),
lang: z.union([z.literal(1), z.literal(2)]).describe('词条语言ID,英文 enUS 为:1,中文 zhCN 为:2'),
}
},
async ({ key, content, lang }) => {
onOpen()
await sleep(1000)
locale.key = key
locale.content = content
locale.lang = lang
await sleep(1000)
addLocale()
return { content: [{ type: 'text', text: `收到: ${key}` }] }
}
)
await server.connect(serverTransport)
});
const MCP_UI_DELAY = 1000; // ms
onMounted(async () => {
try {
const server = new WebMcpServer({
name: 'i18n-management-mcp-server',
version: '1.0.0'
})
const serverTransport = inject('serverTransport')
if (!serverTransport) {
console.error('serverTransport not provided')
return
}
server.registerTool(
'add-i18n-entry',
{
title: '添加国际化词条',
description: '添加国际化词条',
inputSchema: {
key: z.string().describe('词条关键字'),
content: z.string().describe('词条内容'),
lang: z.union([z.literal(1), z.literal(2)]).describe('词条语言ID,英文 enUS 为:1,中文 zhCN 为:2'),
}
},
async ({ key, content, lang }) => {
try {
onOpen()
await sleep(MCP_UI_DELAY)
locale.key = key
locale.content = content
locale.lang = lang
await sleep(MCP_UI_DELAY)
addLocale()
return { content: [{ type: 'text', text: `收到: ${key}` }] }
} catch (error) {
console.error('Failed to add i18n entry via MCP:', error)
return {
content: [{
type: 'text',
text: `添加词条失败: ${error instanceof Error ? error.message : String(error)}`
}],
isError: true
}
}
}
)
await server.connect(serverTransport)
console.log('i18n MCP server connected successfully')
} catch (error) {
console.error('Failed to initialize i18n MCP server:', error)
}
});
🤖 Prompt for AI Agents
In template/tinyvue/src/views/locale/components/add-locale.vue around lines
222-253, replace the loosely-typed inject<any>('serverTransport') with the
correct transport type (use the MCP transport interface/type used elsewhere,
e.g., WebMcpTransport or the same type from info-tab.vue) to improve type
safety; extract the hard-coded 1000ms sleeps into named constants (e.g.,
HANDLER_DELAY_MS) at the top of the module and reference those constants; wrap
the async tool handler and the await server.connect(...) call in try-catch
blocks and log/return meaningful errors instead of letting exceptions bubble;
and decouple UI operations from the MCP handler by emitting an event or calling
a small adapter function that maps the handler result to UI actions
(onOpen/addLocale) so the handler does not directly call UI functions.

Comment on lines +246 to +255
onMounted(async () => {
Promise.all([fetchMenu(), fetchLocalItems()]).finally(() => {
treeLoading.value = false;
});
const server = new WebMcpServer({
name: 'menu-management-mcp-server',
version: '1.0.0'
})
const serverTransport = inject<any>('serverTransport')
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, check if the file exists and view the relevant lines
if [ -f "template/tinyveo/src/views/menu/info/components/info-tab.vue" ]; then
  sed -n '246,255p' "template/tinyveo/src/views/menu/info/components/info-tab.vue"
else
  echo "Checking for correct file path..."
  find . -name "info-tab.vue" -type f 2>/dev/null | head -5
fi

Repository: opentiny/tiny-pro

Length of output: 178


🏁 Script executed:

# Check if @opentiny/next-sdk is in the project dependencies
find . -name "package.json" -type f | xargs grep -l "@opentiny/next-sdk" 2>/dev/null | head -5

Repository: opentiny/tiny-pro

Length of output: 92


🏁 Script executed:

# Check the node_modules for Transport type export from @opentiny/next-sdk
if [ -d "node_modules/@opentiny/next-sdk" ]; then
  echo "=== Checking for Transport type ==="
  find node_modules/@opentiny/next-sdk -name "*.d.ts" -o -name "*.ts" | xargs grep -l "export.*Transport" 2>/dev/null | head -5
else
  echo "@opentiny/next-sdk not found in node_modules"
fi

Repository: opentiny/tiny-pro

Length of output: 105


🏁 Script executed:

# View the file content at the specified lines
sed -n '240,260p' template/tinyvue/src/views/menu/info/components/info-tab.vue

Repository: opentiny/tiny-pro

Length of output: 525


🏁 Script executed:

# Search for Transport type definition in the codebase
rg "type.*Transport|export.*Transport" --type ts --type vue -i

Repository: opentiny/tiny-pro

Length of output: 88


🏁 Script executed:

# Check imports in the info-tab.vue file to understand what's already imported
head -30 template/tinyvue/src/views/menu/info/components/info-tab.vue

Repository: opentiny/tiny-pro

Length of output: 1117


🏁 Script executed:

# Check the package.json to see what version of @opentiny/next-sdk is used
rg "@opentiny/next-sdk" template/tinyvue/package.json -A 1 -B 1

Repository: opentiny/tiny-pro

Length of output: 170


🏁 Script executed:

# Search for all imports from @opentiny/next-sdk to see what types are available
rg "from ['\"]@opentiny/next-sdk['\"]" -A 3 -B 1

Repository: opentiny/tiny-pro

Length of output: 1562


🏁 Script executed:

# Search for Transport or transport-related types in the codebase
rg -i "transport" template/tinyvue/src/views/menu/info/components/info-tab.vue -B 2 -A 2

Repository: opentiny/tiny-pro

Length of output: 243


🏁 Script executed:

# Check if there are any type definitions or .d.ts files in the repo that might define Transport
find . -name "*.d.ts" -type f | xargs grep -l "Transport" 2>/dev/null | head -10

Repository: opentiny/tiny-pro

Length of output: 43


🏁 Script executed:

# Search for how serverTransport is actually used after injection
sed -n '255,280p' template/tinyvue/src/views/menu/info/components/info-tab.vue

Repository: opentiny/tiny-pro

Length of output: 880


🏁 Script executed:

# Check how createMessageChannelPairTransport is used in App.vue to understand transport types
sed -n '1,50p' template/tinyvue/src/App.vue | grep -A 10 "createMessageChannelPairTransport"

Repository: opentiny/tiny-pro

Length of output: 469


🏁 Script executed:

# Search for server.connect usage patterns
rg "server\.connect" -B 3 -A 3

Repository: opentiny/tiny-pro

Length of output: 1058


🏁 Script executed:

# Search for any transport-related type definitions or interfaces in the codebase
rg "transport" template/tinyvue/src -i --type ts --type vue | head -30

Repository: opentiny/tiny-pro

Length of output: 88


🏁 Script executed:

# Check if there's a web_search to verify what's exported from @opentiny/next-sdk
# We'll search the package documentation

Repository: opentiny/tiny-pro

Length of output: 43


🌐 Web query:

@opentiny/next-sdk Transport type export documentation

💡 Result:

You can import the Transport type from the package. Example:

import type { Transport } from '@opentiny/next-sdk'

(See the WebMcpClient connect signature which uses Transport in the OpenTiny NEXT docs.) [1]

Sources

  • OpenTiny NEXT — WebMcpClient (connect signature uses Transport). [1]

Replace any type for serverTransport with proper Transport type.

Line 255 uses any for the injected serverTransport, which bypasses TypeScript's type checking. Import the Transport type from @opentiny/next-sdk and apply it to maintain type safety.

Proposed fix
+import type { Transport } from '@opentiny/next-sdk'

 onMounted(async () => {
   // ...
   const server = new WebMcpServer({
     name: 'menu-management-mcp-server',
     version: '1.0.0'
   })
-  const serverTransport = inject<any>('serverTransport')
+  const serverTransport = inject<Transport>('serverTransport')
+  if (!serverTransport) {
+    console.error('serverTransport not provided')
+    return
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onMounted(async () => {
Promise.all([fetchMenu(), fetchLocalItems()]).finally(() => {
treeLoading.value = false;
});
const server = new WebMcpServer({
name: 'menu-management-mcp-server',
version: '1.0.0'
})
const serverTransport = inject<any>('serverTransport')
import type { Transport } from '@opentiny/next-sdk'
onMounted(async () => {
Promise.all([fetchMenu(), fetchLocalItems()]).finally(() => {
treeLoading.value = false;
});
const server = new WebMcpServer({
name: 'menu-management-mcp-server',
version: '1.0.0'
})
const serverTransport = inject<Transport>('serverTransport')
if (!serverTransport) {
console.error('serverTransport not provided')
return
}
🤖 Prompt for AI Agents
In template/tinyvue/src/views/menu/info/components/info-tab.vue around lines 246
to 255, the injected serverTransport is typed as any which disables TypeScript
checks; import the Transport type from '@opentiny/next-sdk' (add: import type {
Transport } from '@opentiny/next-sdk') and replace
inject<any>('serverTransport') with inject<Transport>('serverTransport') (or
const serverTransport = inject<Transport>('serverTransport') || /* handle
undefined */) so the injected value is strongly typed and handle the possible
undefined return from inject.

Comment on lines +257 to +289
server.registerTool(
'add-menu',
{
title: '添加菜单',
description: '添加菜单',
inputSchema: {
name: z.string().describe('名称'),
order: z.number().describe('优先级').default(0),
parentId: z.number().describe('父菜单ID').optional(),
icon: z.string().describe('图标').optional().default(''),
component: z.string().describe('组件'),
path: z.string().describe('路径'),
locale: z.string().describe('国际化'),
}
},
async ({ name, order, parentId, icon, component, path, locale }) => {
handleAddMenu()
await sleep(1000)
addMenu.value.setMenuInfo({
name,
order,
parentId,
icon,
component,
menuType: "/",
path,
locale,
})
await sleep(1000)
onClickAdd()
return { content: [{ type: 'text', text: `收到: ${name}` }] }
}
)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add error handling and make delays configurable.

The MCP tool registration has several concerns:

  1. Hard-coded delays: Lines 274 and 285 use fixed 1000ms delays. These magic numbers make the code harder to maintain and test. Consider extracting them as named constants or making them configurable.

  2. Missing error handling: The tool handler lacks try-catch blocks. If handleAddMenu(), setMenuInfo(), or onClickAdd() fail, the error will propagate uncaught and the tool will return an incomplete response.

  3. UI orchestration in tool handler: The handler directly manipulates UI state (handleAddMenu(), onClickAdd()), which tightly couples the MCP tool to the component's internal implementation. This pattern may be difficult to test and maintain.

Proposed improvements
+const MCP_UI_DELAY = 1000; // ms - delay for UI updates to be visible
+
 onMounted(async () => {
   // ... server setup ...
   
   server.registerTool(
     'add-menu',
     {
       title: '添加菜单',
       description: '添加菜单',
       inputSchema: {
         name: z.string().describe('名称'),
         order: z.number().describe('优先级').default(0),
         parentId: z.number().describe('父菜单ID').optional(),
         icon: z.string().describe('图标').optional().default(''),
         component: z.string().describe('组件'),
         path: z.string().describe('路径'),
         locale: z.string().describe('国际化'),
       }
     },
     async ({ name, order, parentId, icon, component, path, locale }) => {
+      try {
         handleAddMenu()
-        await sleep(1000)
+        await sleep(MCP_UI_DELAY)
         addMenu.value.setMenuInfo({
           name,
           order,
           parentId,
           icon,
           component,
           menuType: "/",
           path,
           locale,
         })
-        await sleep(1000)
+        await sleep(MCP_UI_DELAY)
         onClickAdd()
         return { content: [{ type: 'text', text: `收到: ${name}` }] }
+      } catch (error) {
+        console.error('Failed to add menu via MCP:', error)
+        return { 
+          content: [{ 
+            type: 'text', 
+            text: `添加菜单失败: ${error instanceof Error ? error.message : String(error)}` 
+          }],
+          isError: true
+        }
+      }
     }
   )

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
template/tinyvue/src/views/menu/info/components/info-tab.vue lines 257-289: the
MCP tool handler uses hard-coded 1000ms sleeps, has no error handling, and
directly manipulates component UI state; extract the delays into named constants
or a configurable prop (e.g., ADD_MENU_DELAY_MS) and replace literal 1000 with
that constant/prop, wrap the entire handler body in a try-catch that
logs/returns a clear error response on failure, and stop tightly coupling to
internal UI functions by emitting component events or calling injected callbacks
instead of directly invoking handleAddMenu() and onClickAdd() so the tool only
triggers abstracted actions and returns success/failure after setMenuInfo and
the delay complete.

}
)
await server.connect(serverTransport)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Add error handling for server connection.

The server.connect() call on line 291 lacks error handling. If the connection fails, the MCP server won't be available and tools won't be accessible, but the component will continue functioning normally without any indication of the problem.

Add try-catch for server connection
-  await server.connect(serverTransport)
+  try {
+    await server.connect(serverTransport)
+    console.log('MCP server connected successfully')
+  } catch (error) {
+    console.error('Failed to connect MCP server:', error)
+    // Consider showing a user notification or disabling MCP features
+  }
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
await server.connect(serverTransport)
try {
await server.connect(serverTransport)
console.log('MCP server connected successfully')
} catch (error) {
console.error('Failed to connect MCP server:', error)
// Consider showing a user notification or disabling MCP features
}
🤖 Prompt for AI Agents
In template/tinyvue/src/views/menu/info/components/info-tab.vue around line 291,
the await server.connect(serverTransport) call lacks error handling; wrap the
connect call in a try-catch, catch and log the error (use existing logger or
console.error), update component state to reflect connection failure (e.g., set
a boolean like serverConnected = false or set an error message reactive
property), and surface a user-visible notification or disable dependent UI/tools
so users know the MCP server is unavailable.

},
async ({ key, content, lang }) => {
onOpen()
await sleep(1000)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

为什么这里要用 sleep 等待?为什么只等待 1 秒?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里主要是为了让整个操作不要太快了,让人能看清楚这个弹窗里的表单

@kagol
Copy link
Member Author

kagol commented Dec 31, 2025

@coderabbitai generate docstrings

@coderabbitai
Copy link

coderabbitai bot commented Dec 31, 2025

✅ Actions performed

Initiated docstring generation; will generate only if new commits exist.

@coderabbitai
Copy link

coderabbitai bot commented Dec 31, 2025

Note

Docstrings generation - SUCCESS
Generated docstrings for this pull request at #166

coderabbitai bot added a commit that referenced this pull request Dec 31, 2025
Docstrings generation was requested by @kagol.

* #165 (comment)

The following files were modified:

* `template/tinyvue/src/utils/base-utils.ts`
url: 'https://agent.opentiny.design/api/v1/webmcp-trial/mcp' // http://localhost:3005/api/v1/webmcp/mcp
})
sessionId.value = sessionID
console.log('sessionId:', sessionId.value)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
console.log('sessionId:', sessionId.value)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants