web-search-mcp
by nishaero
README.md
# web-search-mcp
An MCP server that gives a local language model live information and a read only
view of a Home Assistant installation. It was built for a voice assistant that
runs on Ollama, where the model has no internet access and no knowledge of the
house.
The server speaks MCP over streamable HTTP on port 8765. Any MCP client can use
it, for example Home Assistant's MCP client, Open WebUI through mcpo, or a script.
## Tools
| Tool | What it does |
|---|---|
| `web_search` | Searches the web and the news, ranks the hits against the query, reads the top pages in parallel and returns the passages that match, with dates. Drops old years from the query unless asked for history. |
| `weather_forecast` | Current conditions and a forecast of up to 7 days from Open-Meteo, for the home location or any city. |
| `bundesliga_table`, `bundesliga_team` | Official table, results and fixtures from OpenLigaDB. An example of wrapping a free sports API. |
| `search_home` | Finds any Home Assistant entity from plain words ("kitchen shutter", "solar power"). Matches names, areas, device names and aliases, handles synonyms, and returns the live state with units spelled out for text to speech. |
| `entity_history` | Minimum, maximum and average of a sensor over the last 1 to 168 hours, or the number of state changes for non numeric entities. |
| `person_events` | Person detections per camera: detected now, last detection time and count in the window. Cameras are configured in `CAMERAS_JSON`. |
| `search_documents` | Semantic search over a document collection that Open WebUI keeps in Qdrant. Returns passages with file names so the model can cite the source. |
## Design notes
- **Small answers.** Each page is cut to the paragraphs that match the query
(650 characters by default). A voice model with a small context window cannot
use a full page.
- **Parallel fetching.** Search, news and page downloads run in a thread pool
with a 4 second page timeout, so one slow site does not stall the answer.
- **Read only.** The Home Assistant tools only read. Use a token for a user that
cannot call services.
- **Tool descriptions carry the routing.** The docstrings tell the model when to
use each tool and how to phrase the query. Most of the tuning went into them.
- **Failures are plain sentences.** A tool that fails returns a short message the
model can read out, never a stack trace.
## Run
```bash
cp .env.example .env # fill in what you need
docker build -t web-search-mcp .
docker run -d --name web-search-mcp --env-file .env -p 127.0.0.1:8765:8765 web-search-mcp
```
The MCP endpoint is `http://127.0.0.1:8765/mcp`.
## Security
The server has no authentication of its own. Anyone who can reach port 8765 can
call every tool, including the Home Assistant ones. Keep it bound to localhost or
a private network, or put a reverse proxy with a token in front of it. Do not
publish the port to the internet.
## Tested with
Python 3.14, mcp 2.3.0, ddgs 9.16.0, trafilatura 2.3.1.
## Tests
```bash
pip install -r requirements.txt pytest # for agent-memory-mcp: pip install fastapi uvicorn httpx psycopg2-binary pgvector "mcp>=1.30,<2" pytest
pytest
```
8 tests run without a database, Home Assistant or internet. They cover the parts that are easy to get wrong: query and year handling, picking the right paragraphs from a page, ranking of Home Assistant entities, plain answers when a tool is not configured, and the exact tool list.
## License
MIT
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues