Skip to main content
Glama

차량대 원격 측정을 위한 로컬 MCP 서버

CC3067 Redes 과정의 프로젝트 1, 10분반, Universidad del Valle de Guatemala. Fernando Hernández.

운영자의 컴퓨터에서 실행되는 MCP(Model Context Protocol) 서버로, 차량대의 원격 측정 조회를 언어 모델이 호출할 수 있는 도구로 노출합니다. 이 서버를 통해 사용자가 추적 플랫폼을 열지 않아도 챗봇이 "P-123BCD는 어디에 있나요?" 또는 "이번 주에 가장 많은 킬로미터를 주행한 차량은 어느 것인가요?" 같은 질문에 답할 수 있습니다.

프로토콜은 Python 표준 라이브러리만 사용하여 stdio 위에 처음부터 구현되었습니다. MCP SDK나 JSON-RPC를 처리하는 어떤 라이브러리도 사용하지 않습니다. 이것이 이 프로젝트의 핵심 요구 사항이며 프로토콜 구현 섹션에서 설명합니다.

MCP란 무엇인가

MCP는 언어 모델이 외부 도구를 발견하고 호출하는 방식을 표준화하는 애플리케이션 계층 프로토콜입니다. MCP 서버는 도구 목록을 게시하며, 각 도구는 이름, 설명, 매개변수의 JSON 스키마를 가집니다. 클라이언트(예: Claude Desktop)는 그 목록을 가져와 모델에게 보여 주고, 모델이 도구를 사용하기로 결정하면 클라이언트는 모델이 선택한 인수로 도구를 호출하고 결과를 돌려주어 모델이 자연어로 설명하게 합니다.

기계적으로 MCP는 전송 계층 위에서 동작하는 JSON-RPC 2.0입니다. 이 프로젝트에서 전송 계층은 stdio입니다. 클라이언트는 서버를 자식 프로세스로 시작하고, 두 프로세스는 stdin과 stdout을 통해 줄바꿈으로 구분된 JSON 객체를 교환합니다. 세션은 핸드셰이크(initialize → 응답 → notifications/initialized)로 시작하며, 이후 클라이언트는 tools/list, tools/call, ping을 호출할 수 있습니다.

Related MCP server: NL-to-SQL MCP

왜 차량대인가, 왜 로컬인가

자체 차량대를 보유한 기업은 이미 차량에 GPS와 추적 플랫폼을 갖추고 있습니다. 데이터는 이미 존재하고 완전합니다. 문제는 접근성입니다. 지금은 대시보드를 탐색하고 필터를 적용하고 보고서를 생성해야 하며, 운영을 가장 잘 아는 사람이 플랫폼을 가장 잘 다루지 못하는 경우가 많습니다.

서버는 단지 과정 요구 사항 때문만이 아니라 설계상 로컬에서 실행됩니다. 차량대의 위치는 상업 경로, 고객, 일정을 드러내기 때문입니다. 서버가 운영자의 컴퓨터에 있으면 모델로 전송되는 것은 각 조회의 집계 결과뿐이며, 위치 기록은 절대 전송되지 않습니다.

사전 요구 사항

  • Python 3.11 이상

  • git

  • 선택 사항: Google 지오코딩과 경로 재생성을 위한 Google Maps 키(GOOGLE_MAPS_API_KEY). 키 없이도 모든 기능은 동일하게 작동합니다.

설치

git clone https://github.com/FerAHMz/mcp-local-redes.git
cd mcp-local-redes
python3.11 -m venv .venv
source .venv/bin/activate        # en Windows: .venv\Scripts\activate
pip install -r requirements.txt

데이터베이스 생성

어떤 회사의 실제 데이터도 사용하지 않습니다. 생성기는 과테말라 대도시권의 실제 경로를 따라 7일 동안 15대의 차량을 시뮬레이션하며, 각 차량의 운행 시간 동안 15초마다 보고서를 생성합니다. GPS 노이즈는 σ ≈ 5m이며, 사전에 알고 있는 주입 이벤트(장시간 정차, 과속, 신호 끊김, 지오펜스 진입 및 이탈)도 포함됩니다.

python datos/generador.py

이 과정은 몇 초 안에 datos/flota.db(SQLite, 약 160,000개 위치와 약 1,300개 이벤트)를 생성합니다. 기본적으로 데이터셋은 실행하는 시점에 끝나므로 질문의 "오늘"과 "어제"는 실제 날짜를 가리킵니다. 재현 가능한 데이터셋을 만들려면 종료 시점을 고정합니다.

python datos/generador.py --ahora 2026-08-19T15:30

운행 중인 차량이 꺼진 차량뿐만 아니라 unidades_detenidas에 나타나도록, 근무 시간에 생성하는 것이 좋습니다(또는 근무 시간으로 --ahora를 전달).

경로: 오프라인 모드와 API 모드

기본 경로는 각 경로의 정차 지점과 함께 인코딩된 폴리라인(Google Directions API가 반환하는 형식과 동일)으로 datos/rutas/*.json에 저장되어 있습니다. 생성기는 이 파일들에서 읽어오며 네트워크나 키가 필요하지 않습니다.

Directions API에 다시 요청하려면(예: JSON을 편집하여 정차 지점을 변경하려면):

export GOOGLE_MAPS_API_KEY=...
python datos/generador.py --regenerar-rutas

테스트 클라이언트로 서버 실행하기

서버 자체는 대화형이 아닙니다. stdin에서 JSON을 읽고 stdout에 JSON을 씁니다. 동작을 확인하기 위해 cliente_prueba.py를 작성했습니다. 이 스크립트는 서버를 하위 프로세스로 시작하고, 핸드셰이크를 수행하고, 도구 목록을 나열하고, 호출할 수 있게 하며, 각 방향으로 전달되는 각 메시지를 그대로 인쇄합니다.

python cliente_prueba.py          # interactivo
python cliente_prueba.py --demo   # las herramientas de texto y tres casos de error, de corrido

대화형 모드에서는 도구 번호를 입력하고, 해당 매개변수를 입력한 다음 요청, 응답, 결과를 확인합니다. pinglista도 허용됩니다.

서버는 수동으로도 테스트할 수 있습니다.

printf '{"jsonrpc":"2.0","id":1,"method":"ping"}\n' | python -m servidor.main

서버 로그는 stderr로 이동합니다. --verbose를 사용하면 들어오고 나가는 모든 메시지도 출력합니다.

Claude Desktop에 연결하기

Claude Desktop 구성 파일을 편집합니다.

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

  • Windows: %APPDATA%\Claude\claude_desktop_config.json

그리고 저장소의 절대 경로를 사용하여 서버를 추가합니다.

{
  "mcpServers": {
    "flota": {
      "command": "/ruta/absoluta/mcp-local-redes/.venv/bin/python",
      "args": ["/ruta/absoluta/mcp-local-redes/servidor/main.py"]
    }
  }
}

Windows에서 commandC:\\ruta\\mcp-local-redes\\.venv\\Scripts\\python.exe입니다. Google 지오코딩을 사용하려면 "flota" 안에 "env": {"GOOGLE_MAPS_API_KEY": "..."}를 추가합니다.

Claude Desktop을 다시 시작하면 일곱 개 도구가 나타나며 자연어로 질문할 수 있습니다. 데이터베이스는 저장소 기준 상대 경로인 datos/flota.db에서 탐색됩니다. MCP_FLOTA_DB 변수로 변경할 수 있습니다.

도구

도구

응답하는 질문

매개변수

반환 값

posicion_actual

P-123BCD는 어디에 있나요?

placa

주소, 좌표, 속도, 방향, 엔진 상태, 마지막 보고 시간

unidades_detenidas

30분 이상 정지된 차량은 어느 것인가요?

minutos_minimos (선택 사항, 기본값 30)

차량별로 차량번호, 위치, 정지 시작 시점, 엔진 켜짐 여부

resumen_recorrido

어제 P-456DEF의 운행 기록을 알려 주세요

placa, fecha

킬로미터, 출발·복귀 시간, 정차 지점(횟수, 지속 시간, 가장 긴 정차), 최고·평균 속도, 신호 끊김 구간

mapa_recorrido

어제 P-456DEF의 운행 경로를 지도로 보여 주세요

placa, fecha

OpenStreetMap 위에 경로를 그린 PNG 이미지, 시작점, 끝점, 지속 시간이 포함된 정차 지점, 지오펜스

alertas

이번 주에 과속이 있었나요?

tipo (선택 사항), fecha_inicio, fecha_fin

유형별·차량별 집계, 가장 심각한 이벤트 상세

verificar_geocerca

P-456DEF가 오늘 CEDIS에 진입했나요?

placa, nombre_geocerca, fecha

진입 여부, 입장·퇴장 시간, 방문별 체류 분

reporte_kilometraje

이번 달에 가장 많은 킬로미터를 주행한 차량은?

fecha_inicio, fecha_fin

운영 일수와 일 평균을 포함한 주행거리 기준 차량 순위

날짜 형식은 AAAA-MM-DD입니다. 경보 유형: exceso_velocidad, parada_prolongada, perdida_senal, geocerca_entrada, geocerca_salida.

합성 데이터셋에 정의된 지오펜스: CEDIS Zona 12, Bodega Villa Nueva, Bodega Mixco, CD Zona 18, Bodega Carretera a El Salvador, Centro Histórico. verificar_geocerca는 전체 이름 또는 일부("cedis", "mixco")를 허용합니다.

어떤 도구도 원시 데이터를 반환하지 않습니다. 15대 차량이 7일 동안 15초마다 보고하면 수십만 개의 행이 됩니다. 이를 모델에 보내는 것은 비현실적이고 불필요합니다. 각 도구는 SQL이나 pandas에서 집계하여 계산된 결과를 반환합니다. 응답당 최대 행 수는 servidor/registro.py의 상수 MAX_FILAS = 200이며, 각 도구에 대해 이를 검증하는 테스트가 있습니다.

운행 지도

mapa_recorrido는 텍스트 외의 것을 반환하는 유일한 도구입니다. 그 결과에는 요약을 담은 text 블록과 base64 PNG를 담은 image 블록, 두 개의 콘텐츠 블록이 있으며 Claude Desktop은 이를 채팅에서 바로 표시합니다. 지도는 matplotlib로 그려지며, 배경 타일은 urllib로 OpenStreetMap에서 다운로드됩니다. 네트워크가 없으면 평면 배경 위에 경로를 그립니다.

운행 지도

질문 예시

  • 지금 P-123BCD는 어디에 있나요?

  • 한 시간 넘게 정지해 있는 차량이 있나요?

  • 어제 P-456DEF의 운행 요약을 알려 주세요.

  • 어제 P-789GHJ가 다닌 경로를 지도로 보여 주세요.

  • P-234KLM이 월요일에 몇 번 정차했고 가장 긴 정차는 어디였나요?

  • 이번 주에 과속이 있었나요? 어떤 차량이 가장 많았나요?

  • 지난 7일 동안 신호가 끊긴 차량은 어느 것인가요?

  • P-456DEF가 어제 CEDIS에 들어갔나요? 몇 시에 얼마나 있었나요?

  • 이번 주에 가장 많은 킬로미터를 주행한 차량은 어느 것인가요?

  • 월요일부터 금요일까지 전체 차량대는 몇 킬로미터를 주행했나요?

테스트

python -m pytest tests -v

두 그룹:

  • tests/test_protocolo.py: 올바른 핸드셰이크, initialize 이전의 메서드 거부, 잘못된 JSON → -32700, 잘못된 요청 → -32600, 존재하지 않는 메서드 → -32601, 잘못된 인수 → -32602, 알림은 응답을 생성하지 않음, 응답의 id는 요청의 id와 일치함, 응답은 resulterror를 동시에 가지지 않음, stdio를 통한 실제 프로세스 시작 및 EOF에서의 정상 종료.

  • tests/test_herramientas.py: 고정된 시드로 임시 디렉터리에 생성된 데이터셋을 대상으로 각 도구를 테스트하며, 생성기가 의도적으로 주입한 이벤트(정지시킨 차량, 장시간 정차, 신호 끊김, 과속), 비즈니스 오류, 그리고 어떤 응답도 MAX_FILAS를 초과하지 않는지 확인합니다.

프로토콜 구현

프로토콜과 관련된 모든 것은 sys, json, logging만 사용하여 직접 작성했습니다. pandas, shapely, geopy, matplotlib는 비즈니스 로직이고, requests는 데이터 생성기에서만 사용합니다.

  • servidor/main.py, 전송 계층. stdin을 줄 단위로 읽고 각 응답을 stdout에 \n을 붙여 쓴 다음 flush()를 호출합니다. 모든 로그는 stderr로 보내집니다. stdout은 프로토콜 채널이므로 한 바이트만 추가돼도 프로토콜이 깨지기 때문입니다. EOF에서는 데이터베이스를 닫고 코드 0으로 종료합니다.

  • servidor/jsonrpc.py, JSON-RPC 2.0. 각 메시지를 파싱하고 검증하며, id 키의 존재 여부(값이 아니라)로 요청과 알림을 구분합니다. null도 유효한 id이기 때문입니다. 그리고 표준 코드 -32700, -32600, -32601, -32602, -32603으로 응답과 오류를 구성합니다.

  • servidor/protocolo.py, MCP. 상태 머신(NUEVAINICIALIZANDOLISTA)을 사용한 초기화 핸드셰이크. notifications/initialized가 도착하기 전에는 initializeping이 아닌 모든 메서드가 거부됩니다. 버전 협상: 클라이언트가 요청한 버전을 지원하면 그 버전을 반환하고, 지원하지 않으면 지원하는 최신 버전을 반환합니다. tools/list, tools/call, ping. 처리하지 못하는 알림은 조용히 무시합니다. 알림에 응답하면 클라이언트가 깨지기 때문입니다.

  • servidor/registro.py. inputSchema와 함께 도구 목록이 있으며, 이 스키마를 기준으로 인수를 검증합니다(타입, required, enum). MAX_FILAS는 여기에 있습니다.

JSON-RPC를 MCP에서 분리하기로 한 이유는 둘이 프로토콜의 서로 다른 수준이기 때문입니다: JSON-RPC는 메시지의 형태를 정의하고, MCP는 어떤 메서드가 존재하고 어떤 순서로 호출되는지 정의합니다. 둘을 분리함으로써 세션 없이 메시지 검증을, stdin 없이 상태 머신을 테스트할 수 있었습니다.

가장 신경 쓴 구분은 tools/call에 있습니다: 도구가 존재하지 않거나 인수가 스키마를 충족하지 않으면 프로토콜 오류이며 -32602와 함께 JSON-RPC error로 반환됩니다; 도구가 존재하고 실행되지만 결과가 비즈니스 오류(존재하지 않는 번호판, 데이터가 없는 날)인 경우 isError: true와 읽을 수 있는 메시지가 포함된 result로 반환되어, 모델이 사용자에게 설명할 수 있게 합니다.

실제 세션의 전체 추적(각 메시지의 정확한 JSON 포함)은 docs/protocolo.md에 있습니다.

저장소 구조

mcp-local-redes/
├── servidor/
│   ├── main.py              # punto de entrada, bucle de stdio
│   ├── jsonrpc.py           # construcción y validación de mensajes JSON-RPC 2.0
│   ├── protocolo.py         # handshake, máquina de estados, despacho de métodos
│   ├── registro.py          # registro de herramientas, validación de argumentos, MAX_FILAS
│   └── herramientas/
│       ├── comun.py         # consultas compartidas
│       ├── geocodificacion.py
│       ├── posicion.py
│       ├── detenidas.py
│       ├── recorrido.py
│       ├── mapa.py
│       ├── alertas.py
│       ├── geocercas.py
│       └── kilometraje.py
├── datos/
│   ├── generador.py         # set sintético
│   ├── esquema.sql
│   └── rutas/               # polilíneas guardadas para modo offline
├── cliente_prueba.py
├── tests/
│   ├── test_protocolo.py
│   └── test_herramientas.py
├── docs/
│   └── protocolo.md
└── requirements.txt
F
license - not found
Not graded
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    MCP tool server providing SQLite database access for AI agents.
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    MCP server enabling natural-language querying of SQLite databases via schema discovery, GraphRAG retrieval, and safely guarded read-only SQL execution.
  • F
    license
    Not graded
    quality
    B
    maintenance
    MCP server for AI-powered roadside assistance case management, exposing SQLite-backed tools for querying case counts, statuses, and summaries through natural language via Gemini function calling.
  • A
    license
    A
    quality
    A
    maintenance
    MCP server for chatting with physical-world data from robotics, drones, automotive, and IoT sources using natural language. It generates auditable SQL queries over Apache Arrow/DuckDB to let you analyze, summarize, and build data pipelines.
    18
    393
    Apache 2.0

View all related MCP servers

Related MCP Connectors

  • GibsonAI MCP server: manage your databases with natural language

  • MCP server exposing the Backtest360 engine API as tools for AI agents.

  • MCP server for managing Prisma Postgres.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/FerAHMz/mcp-local-redes'

If you have feedback or need assistance with the MCP directory API, please join our Discord server