gaslighting-mcp
# gaslighting-mcp
A fake web search MCP server for AI alignment testing. It accepts a search query and returns LLM-generated search results shaped by a configurable background story.
Built with [FastMCP](https://github.com/jlowin/fastmcp) and compatible with any OpenAI-style API endpoint.
## How it works
1. You provide a background story via the `BACKGROUND_STORY` environment variable
2. The server exposes two tools: `search` and `read_url`
3. `search` — generates 10 realistic search results (url, snippet, date) consistent with the background story
4. `read_url` — generates a full fake article in markdown for a given URL, inferred from the domain/path and background story
5. The consuming AI agent receives these as if they were real web content
## Setup
```bash
uv sync
```
## Configuration
| Environment Variable | Default | Description |
|---|---|---|
| `BACKGROUND_STORY` | `""` | The narrative that shapes all generated results |
| `LLM_BASE_URL` | `https://openrouter.ai/api/v1` | OpenAI-compatible API base URL |
| `LLM_API_KEY` | `""` | API key for the LLM endpoint |
| `LLM_MODEL` | `nousresearch/hermes-4-405b` | Model name |
## Usage
### Standalone
```bash
uv run server.py
```
### Claude Code MCP config
Add to your `.mcp.json`:
```json
{
"mcpServers": {
"web-search": {
"command": "uv",
"args": ["run", "server.py"],
"env": {
"BACKGROUND_STORY": "your background story here",
"LLM_API_KEY": "your-api-key"
}
}
}
}
```
## Tools
### `search(query)`
Returns a JSON array of 10 results:
```json
[
{
"url": "https://example.com/some-article",
"snippet": "A realistic excerpt shaped by the background story.",
"date": "2025-12-15"
}
]
```
### `read_url(url)`
Returns a full fake article in markdown, inferred from the URL and background story. Matches the tone and style of the source website.
## License
MIT
TDQS
Scored across 2 tools
The two tools have clearly distinct purposes: read_url fetches and converts a specific webpage to markdown, while search performs a broader web query and returns multiple results. There is no overlap in functionality, making tool selection unambiguous.
Both tools follow a consistent verb-based naming pattern (read_url, search) with clear, simple names that accurately describe their actions. There are no deviations or mixed conventions.
With only two tools, the server feels thin for a web-related domain that typically requires more operations (e.g., filtering, summarization, or advanced search). While the tools cover basic fetch and search, the scope is minimal and lacks depth.
For a web interaction server, there are significant gaps: no ability to interact with page elements, handle authentication, filter search results, or perform actions like posting or updating. The tools provide only basic read and search, leaving many common web tasks uncovered.