---
title: DevLog @ 2025.04.28
category: DevLog
date: 2025-04-28
---
안녕하세요 여러분, [@LemonNeko](https://github.com/LemonNekoGH) 입니다. 오늘도 개발 이야기를 나누러 왔습니다.
## 낮 시간의 일기
일주일 전, AIRI 가 휴대폰에 연결할 수 있도록 MCP 서버 [AIRI-android](https://github.com/LemonNekoGH/AIRI-android) 를 만들었습니다. 하지만 이건 AIRI 가 Android 폰을 조작하게 만드는 일의 전반부일 뿐이었습니다. AIRI 도 MCP 서버와 상호작용할 수 있어야 했으니까요.
지난 이틀 동안 Tauri 플러그인 [#144](https://github.com/moeru-ai/AIRI/pull/144) 를 작성해 후반부를 마쳤습니다. 이제 AIRI 는 MCP 서버와 상호작용할 수 있고, 기존의 모든 MCP 서버와 함께 동작합니다.
관심 있으시면 아래 두 영상을 봐 주세요. 첫 번째는 AIRI 의 MCP 서버 설정을, 두 번째는 AIRI 가 Android 폰과 상호작용하는 모습을 보여 줍니다.
AIRI 의 MCP 서버 설정AIRI 가 휴대폰에 `Hello World` 를 입력하는 모습
개발 중 생각을 정리하려고 LLM 이 Android 폰을 호출하는 흐름을 그림으로 그려 봤습니다:
이제 개발 과정을 나눠 보겠습니다.
## Tauri 플러그인 개발
사실 처음부터 완전한 Tauri 플러그인을 만들 생각은 없었습니다. 그저 JavaScript 쪽에 명령 몇 개를 노출하고 싶었을 뿐입니다:
```rust
#[Tauri::command]
fn list_tools() -> Vec {
// 나중에 구현
}
```
그리고 이를 호출할 유틸리티 함수를 조금 작성하면 되겠지요:
```javascript
import { invoke } from '@Tauri-apps/api/core'
export const mcp = [
{
name: 'list_tools',
description: 'List all tools',
execute: async () => {
return await invoke('list_tools')
}
}
]
```
그런데 곧, 명령 안에서 MCP 클라이언트를 쓰려면 MCP 클라이언트를 Tauri 가 관리하는 상태(state)의 일부로 두어야 한다는 걸 알게 됐습니다:
```rust
// main.rs
fn main() {
Tauri::Builder::default()
.setup(|app| {
app.manage(State::new(Mutex::new::