feat: add MCP server for AI tool integration#226
Conversation
Embeds an MCP (Model Context Protocol) server in the app using the official kotlin-sdk. Developers can toggle it on via Settings > Developer > MCP Server, which starts a foreground service with a Ktor CIO server on port 8765 exposing 6 read-only tools: get_transactions, get_spending_summary, get_categories, search_transactions, get_balance_overview, and get_subscriptions. Also upgrades Ktor from 2.3.12 to 3.2.3 for SDK compatibility.
Greptile SummaryThis PR adds an embedded MCP (Model Context Protocol) server as a developer-only feature, exposing 6 read-only financial data tools over Streamable HTTP via Ktor CIO. The server runs as a foreground service on port 8765 and is gated behind a developer mode toggle in Settings. Key issues found:
Confidence Score: 3/5Not safe to merge as-is — the 0.0.0.0 binding is a security hole for a financial app, and the total_matching logic bug breaks the primary pagination contract for AI clients. Two concrete issues block a clean merge: the server binding exposes sensitive financial data on the local network without any auth, and the total_matching field is structurally wrong making pagination unusable for AI tools. The main thread blocking in onDestroy is also a reliability concern. The overall architecture is solid and the remaining non-mcp changes (preferences, settings UI, manifest) are correct. McpServer.kt (0.0.0.0 binding), McpToolHandler.kt (total_matching, in-memory filtering), McpServerService.kt (blocking stop on main thread) Important Files Changed
Sequence DiagramsequenceDiagram
participant UI as SettingsScreen
participant VM as SettingsViewModel
participant Prefs as UserPreferencesRepository
participant Svc as McpServerService
participant Server as McpServer (Ktor/CIO)
participant Tool as McpToolHandler
participant DB as Room DAOs
participant Client as MCP Client
UI->>VM: toggleMcpServer(true)
VM->>Prefs: setMcpServerEnabled(true)
VM->>Svc: start(context, port=8765)
Svc->>Svc: startForeground(notification)
Svc->>Server: McpServer(toolHandler, port).start()
Server->>Server: embeddedServer(CIO, host="0.0.0.0", port=8765)
Note over Server: ⚠️ binds all interfaces
Client->>Server: POST /mcp (tool call)
Server->>Tool: invoke registered tool
Tool->>DB: query DAO (getTransactionsBetweenDatesList etc.)
DB-->>Tool: List<Entity>
Tool-->>Server: CallToolResult(JSON)
Server-->>Client: JSON response
UI->>VM: toggleDeveloperMode(false)
VM->>VM: toggleMcpServer(false)
VM->>Prefs: setMcpServerEnabled(false)
VM->>Svc: stop(context)
Svc->>Svc: onDestroy() [main thread]
Svc->>Server: stop() ⚠️ blocks up to 2s on main thread
|
Summary
kotlin-sdk-server(v0.9.0)get_transactions,get_spending_summary,get_categories,search_transactions,get_balance_overview,get_subscriptionsUsage
adb forward tcp:8765 tcp:8765http://localhost:8765/mcpTest plan
curl http://localhost:8765/healthreturns OK