mirror of
https://github.com/kennethnym/aris.git
synced 2026-06-13 19:11:18 +01:00
feat: add google maps mcp source (#125)
This commit is contained in:
135
packages/freya-source-google-maps/src/google-maps-source.test.ts
Normal file
135
packages/freya-source-google-maps/src/google-maps-source.test.ts
Normal file
@@ -0,0 +1,135 @@
|
||||
import type {
|
||||
McpCallToolParams,
|
||||
McpCallToolResult,
|
||||
McpClient,
|
||||
McpListToolsResult,
|
||||
McpReadResourceParams,
|
||||
McpReadResourceResult,
|
||||
} from "@freya/source-mcp"
|
||||
|
||||
import { describe, expect, test } from "bun:test"
|
||||
|
||||
import { GoogleMapsAction, GoogleMapsSource, GoogleMapsSourceId, GoogleMapsTool } from "./index"
|
||||
|
||||
class MockMcpClient implements McpClient {
|
||||
readonly calls: McpCallToolParams[] = []
|
||||
|
||||
async listTools(): Promise<McpListToolsResult> {
|
||||
return {
|
||||
tools: Object.values(GoogleMapsTool).map((name) => ({
|
||||
name,
|
||||
description: `${name} description`,
|
||||
})),
|
||||
}
|
||||
}
|
||||
|
||||
async readResource(_params: McpReadResourceParams): Promise<McpReadResourceResult> {
|
||||
throw new Error("unexpected resource read")
|
||||
}
|
||||
|
||||
async callTool(params: McpCallToolParams): Promise<McpCallToolResult> {
|
||||
this.calls.push(params)
|
||||
return {
|
||||
structuredContent: {
|
||||
tool: params.name,
|
||||
arguments: params.arguments ?? {},
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
describe("GoogleMapsSource", () => {
|
||||
test("uses the Google Maps source id", () => {
|
||||
const source = new GoogleMapsSource({ client: new MockMcpClient() })
|
||||
expect(source.id).toBe(GoogleMapsSourceId)
|
||||
})
|
||||
|
||||
test("exposes documented Google Maps MCP tools as actions", async () => {
|
||||
const source = new GoogleMapsSource({ client: new MockMcpClient() })
|
||||
|
||||
const actions = await source.listActions()
|
||||
|
||||
expect(Object.keys(actions).sort()).toEqual(Object.values(GoogleMapsAction).sort())
|
||||
expect(actions[GoogleMapsAction.SearchPlaces]!.id).toBe(GoogleMapsAction.SearchPlaces)
|
||||
})
|
||||
|
||||
test("maps action execution to the underlying MCP tool", async () => {
|
||||
const client = new MockMcpClient()
|
||||
const source = new GoogleMapsSource({ client })
|
||||
|
||||
const result = await source.executeAction(GoogleMapsAction.SearchPlaces, {
|
||||
textQuery: "coffee shops near Golden Gate Park",
|
||||
regionCode: "US",
|
||||
})
|
||||
|
||||
expect(client.calls).toEqual([
|
||||
{
|
||||
name: GoogleMapsTool.SearchPlaces,
|
||||
arguments: {
|
||||
textQuery: "coffee shops near Golden Gate Park",
|
||||
regionCode: "US",
|
||||
},
|
||||
},
|
||||
])
|
||||
expect(result).toEqual({
|
||||
tool: GoogleMapsTool.SearchPlaces,
|
||||
arguments: {
|
||||
textQuery: "coffee shops near Golden Gate Park",
|
||||
regionCode: "US",
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
test("validates action input before calling the MCP tool", async () => {
|
||||
const client = new MockMcpClient()
|
||||
const source = new GoogleMapsSource({ client })
|
||||
|
||||
await expectRejectsWithMessage(
|
||||
source.executeAction(GoogleMapsAction.SearchPlaces, {}),
|
||||
"textQuery must be a string",
|
||||
)
|
||||
expect(client.calls).toEqual([])
|
||||
})
|
||||
|
||||
test("validates resolve names query objects", async () => {
|
||||
const client = new MockMcpClient()
|
||||
const source = new GoogleMapsSource({ client })
|
||||
|
||||
await expectRejectsWithMessage(
|
||||
source.executeAction(GoogleMapsAction.ResolveNames, { queries: [{}] }),
|
||||
"queries[0].text must be a string",
|
||||
)
|
||||
expect(client.calls).toEqual([])
|
||||
})
|
||||
|
||||
test("does not produce feed items or context by default", async () => {
|
||||
const source = new GoogleMapsSource({ client: new MockMcpClient() })
|
||||
|
||||
const contextEntries = await source.fetchContext(undefined as never)
|
||||
const items = await source.fetchItems(undefined as never)
|
||||
|
||||
expect(contextEntries).toBeNull()
|
||||
expect(items).toEqual([])
|
||||
})
|
||||
})
|
||||
|
||||
async function expectRejectsWithMessage(
|
||||
promise: Promise<unknown>,
|
||||
expectedMessage: string,
|
||||
): Promise<void> {
|
||||
try {
|
||||
await promise
|
||||
} catch (err) {
|
||||
expect(errorMessage(err)).toContain(expectedMessage)
|
||||
return
|
||||
}
|
||||
|
||||
throw new Error(`Expected promise to reject with "${expectedMessage}"`)
|
||||
}
|
||||
|
||||
function errorMessage(err: unknown): string {
|
||||
if (err instanceof Error) {
|
||||
return err.message
|
||||
}
|
||||
return String(err)
|
||||
}
|
||||
Reference in New Issue
Block a user