HERE Discover API で周辺情報を検索してくれる MCP サーバーのメモ
この記事は HERE Advent Calendar 2025 の 20 日目の記事です。
HERE Discover API で周辺情報を検索してくれる MCP サーバーのメモです。
背景

HUG-JP Meetup vol.1 で登壇した ときの MCP サーバーの出来が結構よかったので、この機会にまとめておきます。
HERE API キーの取得

HERE API を使うにはAPIキーが必要です。HERE ポータル からアカウント登録して取得できます。
GPS デバイスと連携するものです
GPS デバイスひとつを LT まで生存させるためにデカい Anker バッテリーで供給してる #HEREUGJP #BuildWithHERE pic.twitter.com/DNS4oFNbhd
— Tanaka Seigo (@1ft_seabass) September 17, 2025
LT でライブデモしていましたが自作の GPS デバイスと連携するものです。
このようなデバイスで、同一のローカルネットワーク上から、以下のような JSON データが取得できる想定です。
URL 例
http://192.168.XXX.XXX/gps
データ例
{
"lat": 35.681236,
"lng": 139.767125,
"alt": 40.5,
"satellites": 8,
"valid": true
}
package.json の様子
2025 年 9 月時点 tsx でより手軽に TypeScript な MCP サーバーを動かすメモ を前提で、ライブラリや Claude Desktop から実行するスクリプト実行は以下のようになっています。
{
"name": "here-mcp-sample",
"version": "1.0.0",
"type": "module",
"scripts": {
"here-server": "tsx --no-warnings here-server.ts"
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.18.0",
"dotenv": "^17.2.2",
"zod": "^3.25.76"
},
"devDependencies": {
"@types/node": "^24.5.0",
"tsx": "^4.20.5"
}
}
here-server.ts の内容
実際こういったコードになっております。

- HERE API や GPS デバイスのレスポンス用の型定義
- 「カフェ」→「cafe」など日本語対応を想定したカテゴリマッピング
- GPS デバイスから位置情報を取得する関数
- HERE Discover API で周辺検索する関数
- MCP サーバーとして 2 つのツールを定義
- get_gps_location の GPS 位置取得
- search_nearby_places の周辺スポット検索
といったことをしています。
import 'dotenv/config';
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ListToolsRequestSchema,
Tool,
} from '@modelcontextprotocol/sdk/types.js';
// HERE API用の型定義
interface HereDiscoverResponse {
items: Array<{
title: string;
id: string;
ontologyId?: string;
resultType: string;
address: {
label: string;
countryCode: string;
countryName: string;
stateCode?: string;
state?: string;
county?: string;
city: string;
district?: string;
street?: string;
postalCode?: string;
houseNumber?: string;
};
position: {
lat: number;
lng: number;
};
access?: Array<{
lat: number;
lng: number;
}>;
distance?: number;
categories: Array<{
id: string;
name: string;
primary?: boolean;
}>;
contacts?: Array<{
phone?: Array<{
value: string;
categories?: Array<{ id: string }>;
}>;
www?: Array<{
value: string;
categories?: Array<{ id: string }>;
}>;
email?: Array<{
value: string;
categories?: Array<{ id: string }>;
}>;
}>;
openingHours?: Array<{
categories?: Array<{ id: string }>;
text: string[];
isOpen: boolean;
structured?: Array<{
start: string;
duration: string;
recurrence: string;
}>;
}>;
}>;
}
// GPS位置情報の型定義
interface GPSLocation {
latitude: number;
longitude: number;
accuracy?: number;
timestamp: string;
}
// GPSデバイスAPIのレスポンス型定義
interface GPSDeviceResponse {
lat: number;
lng: number;
alt: number;
satellites: number;
valid: boolean;
}
// HERE APIキー(環境変数から取得)
const HERE_API_KEY = process.env.HERE_API_KEY;
// GPSデバイスの URL の例
const GPS_DEVICE_URL = 'http://192.168.XXX.XXX/gps';
// カテゴリマッピング(日本語→HERE APIクエリ)
const CATEGORY_MAP: Record<string, string> = {
'カフェ': 'cafe',
'コーヒー': 'cafe',
'coffee': 'cafe',
'レストラン': 'restaurant',
'食事': 'restaurant',
'restaurant': 'restaurant',
'コンビニ': 'convenience store',
'買い物': 'shopping',
'shopping': 'shopping',
'銀行': 'bank',
'bank': 'bank',
'病院': 'hospital',
'hospital': 'hospital',
'ガソリンスタンド': 'gas station',
'gas station': 'gas station'
};
const server = new Server(
{
name: 'here-mcp-server',
version: '1.0.0',
},
{
capabilities: {
tools: {},
},
}
);
// GPS位置取得ツール
async function getGPSLocation(): Promise<GPSLocation> {
try {
const response = await fetch(GPS_DEVICE_URL);
if (!response.ok) {
throw new Error(`GPSデバイスAPI Error: ${response.status} ${response.statusText}`);
}
const gpsData = await response.json() as GPSDeviceResponse;
// GPSデータが有効かチェック
if (!gpsData.valid) {
throw new Error('GPSデータが無効です(GPS信号を受信できていません)');
}
// 衛星数が少ない場合の警告
if (gpsData.satellites < 4) {
console.warn(`GPS衛星数が少なめです: ${gpsData.satellites}個`);
}
// 精度を衛星数から推定(衛星数が多いほど精度が高い)
const estimatedAccuracy = Math.max(10 - gpsData.satellites, 1);
return {
latitude: gpsData.lat,
longitude: gpsData.lng,
accuracy: estimatedAccuracy,
timestamp: new Date().toISOString()
};
} catch (error) {
console.error('GPSデバイスからの位置取得エラー:', error);
throw new Error(`GPSデバイスから位置情報を取得できませんでした: ${error instanceof Error ? error.message : String(error)}`);
}
}
// HERE Discover APIで周辺検索
async function searchNearbyPlaces(
latitude: number,
longitude: number,
category: string,
limit: number = 10
): Promise<HereDiscoverResponse> {
if (!HERE_API_KEY) {
throw new Error('HERE_API_KEY環境変数が設定されていません');
}
// カテゴリマッピングを適用
const searchQuery = CATEGORY_MAP[category.toLowerCase()] || category;
const url = new URL('https://discover.search.hereapi.com/v1/discover');
url.searchParams.set('at', `${latitude},${longitude}`);
url.searchParams.set('limit', limit.toString());
url.searchParams.set('q', searchQuery);
url.searchParams.set('in', 'countryCode:JPN'); // 日本に限定
url.searchParams.set('apiKey', HERE_API_KEY);
try {
const response = await fetch(url.toString());
if (!response.ok) {
throw new Error(`HERE API Error: ${response.status} ${response.statusText}`);
}
const data = await response.json() as HereDiscoverResponse;
return data;
} catch (error) {
console.error('HERE API呼び出しエラー:', error);
throw error;
}
}
// ツールリストの定義
server.setRequestHandler(ListToolsRequestSchema, async () => {
return {
tools: [
{
name: 'get_gps_location',
description: 'デバイスから位置情報を取得するツールです',
inputSchema: {
type: 'object',
properties: {},
required: [],
},
} satisfies Tool,
{
name: 'search_nearby_places',
description: '指定された位置の周辺で特定のカテゴリの場所を検索するツールです(例:カフェ、レストラン、コンビニなど)',
inputSchema: {
type: 'object',
properties: {
latitude: {
type: 'number',
description: '検索の中心となる緯度',
},
longitude: {
type: 'number',
description: '検索の中心となる経度',
},
category: {
type: 'string',
description: '検索するカテゴリ(カフェ、レストラン、コンビニ、買い物、銀行、病院など)',
},
limit: {
type: 'number',
description: '検索結果の最大件数(デフォルト: 10)',
default: 10,
},
},
required: ['latitude', 'longitude', 'category'],
},
} satisfies Tool,
],
};
});
// ツール呼び出しハンドラー
server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
try {
switch (name) {
case 'get_gps_location': {
const location = await getGPSLocation();
return {
content: [
{
type: 'text',
text: `リアルタイムGPS位置を取得しました:
緯度: ${location.latitude}
経度: ${location.longitude}
推定精度: ${location.accuracy}m
取得時刻: ${location.timestamp}
GPSデバイス(192.168.XXX.XXX)からの実際の位置情報です。`,
},
],
};
}
case 'search_nearby_places': {
const { latitude, longitude, category, limit = 10 } = args as {
latitude: number;
longitude: number;
category: string;
limit?: number;
};
const results = await searchNearbyPlaces(latitude, longitude, category, limit);
if (results.items.length === 0) {
return {
content: [
{
type: 'text',
text: `指定された位置(緯度: ${latitude}, 経度: ${longitude})周辺で「${category}」に該当する場所は見つかりませんでした。`,
},
],
};
}
const resultText = results.items.map((item, index) => {
const distance = item.distance ? `(約${item.distance}m)` : '';
const phone = item.contacts?.[0]?.phone?.[0]?.value || '不明';
const website = item.contacts?.[0]?.www?.[0]?.value || 'なし';
const categories = item.categories.map(cat => cat.name).join(', ');
const openingHours = item.openingHours?.[0]?.text?.join(', ') || '営業時間不明';
return `${index + 1}. ${item.title}${distance}
住所: ${item.address.label}
カテゴリ: ${categories}
電話: ${phone}
ウェブサイト: ${website}
営業時間: ${openingHours}
座標: ${item.position.lat}, ${item.position.lng}`;
}).join('\n\n');
return {
content: [
{
type: 'text',
text: `「${category}」の検索結果(${results.items.length}件見つかりました):
${resultText}`,
},
],
};
}
default:
throw new Error(`不明なツール: ${name}`);
}
} catch (error) {
const errorMessage = error instanceof Error ? error.message : String(error);
return {
content: [
{
type: 'text',
text: `エラーが発生しました: ${errorMessage}`,
},
],
isError: true,
};
}
});
async function main() {
const transport = new StdioServerTransport();
await server.connect(transport);
console.error('HERE MCP Server が開始されました');
}
main();
設定を実際の環境に合わせる
.env ファイルを作成して HERE API キーを設定します。
HERE_API_KEY=your-api-key-here
また、ソースコード内の GPS_DEVICE_URL は自分の GPS デバイスの IP アドレスに合わせて変更してください。
const GPS_DEVICE_URL = 'http://192.168.XXX.XXX/gps';
Claude Desktop の設定
Claude Desktop の設定ファイル claude_desktop_config.json に以下を追加します。
"mcpServers": {
"here-server": {
"command": "npm",
"args": [
"--prefix",
"C:\\workspace\\here-mcp-sample",
"run",
"here-server",
"--silent"
]
}
}
--prefix のパスは自分の環境に合わせて変更してください。
実際の動作

「デバイスから位置情報取得して」と聞くと get_gps_location ツールが動いて、GPS デバイスから現在地を取得してくれます。
まずこれで GPS 情報が Claude が記憶します。準備完了。

取得した位置情報をもとに「近くのコンビニ教えて」と聞くと、search_nearby_places ツールで HERE API を使った周辺検索が動きます。
ちゃんと距離順で近くのコンビニが返ってきます!