* adding ability to tag listings eg if you have applied to it / adding ability to add notes to a listing * storing the date when a status was set
Fredy MCP Server
The Fredy MCP Server exposes your real estate jobs and listings data to LLM clients. It supports two transports:
- Stdio: for local LLM clients (Claude Desktop, LM Studio, llm-cli, mcp-cli, etc.)
- Streamable HTTP: for remote LLM clients (ChatGPT, cloud-hosted agents, etc.)
Authentication
All MCP access is token-based based. Every Fredy user is automatically assigned a permanent, non-expiring MCP token when their account is created. This token is a secret and should be treated like a password.
Where to find your token
MCP tokens are displayed in the User Management list (Admin → Users). Each user's token is shown in the "MCP Token" column.
Important: MCP tokens never expire. They are permanent secrets tied to each user account. If a token is compromised, you must change the token! If you chose to use a token from an admin account, the LLM can query information from ALL jobs/listings.
Available Tools
| Tool | Description |
|---|---|
list_jobs |
List real estate search jobs with pagination and text filtering |
get_job |
Get detailed information about a specific job |
list_listings |
Search and list real estate listings with pagination, text search, and filters |
get_listing |
Get full details of a single listing |
get_current_date_time |
Gets the current date/time for the llm to be used |
Tool Details
list_jobs
page(number, optional) – Page number (default: 1)pageSize(number, optional) – Results per page (default: 50, max: 1000). Use pagination to fetch more.filter(string, optional) – Free-text filter on job name
Response: markdown table with columns ID, Name, Enabled, Active Listings. Includes summary and pagination info.
get_job
jobId(string, required) – The job ID to retrieve
list_listings
page(number, optional) – Page number (default: 1)pageSize(number, optional) – Results per page (default: 50, max: 1000). Use pagination to fetch more.filter(string, optional) – Free-text search across title, address, provider, linkjobId(string, optional) – Filter listings by job IDactiveOnly(boolean, optional) – When true, only show active listingsprovider(string, optional) – Filter by provider namecreatedAfter(number, optional) – Only include listings created at or after this unix timestamp in milliseconds (e.g.1772008362564). Useful for queries like "give me all listings from today".createdBefore(number, optional) – Only include listings created at or before this unix timestamp in milliseconds (e.g.1772008362564).minPrice(number, optional) – Only include listings with price >= this value (e.g.500). Numeric, no currency symbol.maxPrice(number, optional) – Only include listings with price <= this value (e.g.1500). Numeric, no currency symbol.sortField(string, optional) – Sort by: created_at, price, size, provider, title, is_activesortDir(string, optional) – Sort direction: asc or desc
Response: markdown table with columns ID, Title, Address, Price, Size, Provider, Active, Created, Job. Includes summary and pagination info. Use get_listing for full details.
Note: All timestamps are unix timestamps in milliseconds (e.g.
1772008362564), not seconds.
get_listing
listingId(string, required) – The listing ID to retrieve
Usage with Local LLM (stdio transport)
The stdio transport communicates over stdin/stdout and is ideal for local LLM tools.
Quick Start
MCP_TOKEN=fredy_<your-token> node mcp/stdio.js
# or
MCP_TOKEN=fredy_<your-token> yarn mcp:stdio
Testing with MCP Inspector
The MCP Inspector lets you interactively test your MCP server in a browser UI.
npx @modelcontextprotocol/inspector -e MCP_TOKEN=fredy_<your-token> -- node mcp/stdio.js
Once the inspector is running, open the URL shown in your terminal (usually http://localhost:6274). You can then:
- Click Connect to establish the stdio connection
- Go to the Tools tab to see all available tools
- Select a tool, fill in parameters, and click Run to test it
LM Studio Configuration
LM Studio supports MCP servers natively, allowing your local LLM to access Fredy's jobs and listings data.
Setup
-
Open LM Studio and load a model that supports tool use (e.g., Qwen 2.5, Llama 3.1, Mistral, etc.)
-
In the right side under Integrations click on "# install" and "edit mcp.json"
-
Edit the LM Studio MCP config file directly (
~/.lmstudio/config/mcp.jsonor via the UI export):{ "mcpServers": { "fredy": { "command": "node", "args": ["/absolute/path/to/fredy/mcp/stdio.js"], "env": { "MCP_TOKEN": "fredy_<your-token>" } } } } -
Toggle the server on: LM Studio will spawn the stdio process and connect
-
You should see the Fredy tools appear as available tools
Suggestion on LLM
After testing numerous LLM's, I got the best results with Qwen 3.5 or Qwen 2.5.. E.g. Qwen2.5-14B-Instruct-1M-8bit.
Usage
Once connected, simply ask your LLM about your real estate data in natural language:
- "Show me all my active search jobs"
- "List the latest listings from my Berlin apartment search"
- "Get details for listing XYZ"
- "What are the cheapest listings across all my jobs?"
The LLM will automatically call the appropriate Fredy MCP tools and present the results.
Tip: Make sure Fredy is running and the database is accessible before starting the MCP server in LM Studio. The stdio transport initializes its own database connection, so Fredy's main process does not need to be running, but the database file must exist and be up-to-date (migrations applied).
Claude Desktop Configuration
Claude Desktop supports MCP servers natively via its developer settings.
Setup
-
Open Claude Desktop
-
Go to Settings → Developer → Edit Config - this opens the
claude_desktop_config.jsonfile -
Add the
fredyserver to themcpServersobject:{ "mcpServers": { "fredy": { "command": "/opt/homebrew/opt/node@22/bin/node", "args": ["/absolute/path/to/fredy/lib/mcp/stdio.js"], "env": { "MCP_TOKEN": "fredy_<your-token>" } } } }Replace
/absolute/path/to/fredywith the actual path on your machine (e.g./Users/you/dev/fredy).Important: Claude Desktop launches with a restricted
PATHand often cannot findnodeby name. Always use the full absolute path to the node binary. Find yours by runningwhich nodein a terminal. Common locations:- Homebrew (default):
/opt/homebrew/bin/node - Homebrew (versioned, e.g. node@22):
/opt/homebrew/opt/node@22/bin/node - nvm:
/Users/<you>/.nvm/versions/node/<version>/bin/node
- Homebrew (default):
-
Save the file and restart Claude Desktop
-
You should see a hammer icon (🔨) in the chat input - click it to confirm the Fredy tools are listed
Usage
Once connected, simply ask Claude about your real estate data:
- "Show me all my active search jobs"
- "List the latest listings from my Berlin apartment search"
- "What are the cheapest apartments added this week?"
Claude will automatically call the appropriate Fredy MCP tools.
Note: Fredy's main web process does not need to be running - the stdio transport opens its own database connection directly. But the SQLite database file must exist and migrations must have been applied.
Usage with Remote LLM (Streamable HTTP transport)
The HTTP transport is automatically available when Fredy is running. It uses the MCP Streamable HTTP protocol at:
POST /api/mcp – JSON-RPC messages (initialize, tool calls)
GET /api/mcp – SSE stream for server-initiated notifications
DELETE /api/mcp – Terminate session
Authentication
All requests must include the token as a Bearer token:
Authorization: Bearer fredy_<your-token>
Example: Initialize a session
curl -X POST http://localhost:9998/api/mcp \
-H "Content-Type: application/json" \
-H "Authorization: Bearer fredy_<your-token>" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": { "name": "test-client", "version": "1.0.0" }
}
}'
Example: Call a tool
curl -X POST http://localhost:9998/api/mcp \
-H "Content-Type: application/json" \
-H "Authorization: Bearer fredy_<your-token>" \
-H "Mcp-Session-Id: <session-id-from-init-response>" \
-d '{
"jsonrpc": "2.0",
"id": 2,
"method": "tools/call",
"params": {
"name": "list_jobs",
"arguments": { "page": 1, "pageSize": 10 }
}
}'
Security
- Every user is automatically assigned a permanent MCP token at account creation – tokens never expire
- Tokens are cryptographically random (256-bit) and prefixed with
fredy_ - Each token is scoped to a single user – the LLM can only access that user's data
- Non-admin users only see their own jobs and jobs shared with them
- Tokens are stored in the
mcp_tokencolumn of theuserstable - Tokens are deleted automatically when the owning user is removed
- The
/api/mcpendpoint uses Bearer token auth (independent of cookie-session) - Treat MCP tokens like passwords – do not share them publicly
Response Format
All tool responses use markdown instead of JSON for maximum LLM readability and token efficiency:
- List responses (list_jobs, list_listings) use markdown tables with a summary line and pagination footer
- Detail responses (get_job, get_listing) use markdown key-value lists
- Error responses include the tool name and error message
Example list response:
**Tool:** list_listings | **Status:** OK
Found **85** listing(s). Showing page 1 of 2 (50 on this page). More pages available - use page=2 to continue.
| ID | Title | Address | Price | Size | Provider | Active | Created | Job |
|----|-------|---------|-------|------|----------|--------|---------|-----|
| abc123 | Nice flat | Berlin | 1200 | 70 | immoscout | yes | 2026-02-25 10:30:00 | My Search |
| ... | ... | ... | ... | ... | ... | ... | ... | ... |
Use **get_listing** with an ID for full details (description, link, image).
**Page:** 1/2 | **Has more:** yes
Example detail response:
**Tool:** get_listing | **Status:** OK
### Listing: Nice flat
- **ID:** abc123
- **Title:** Nice flat
- **Address:** Berlin
- **Price:** 1200
- **Size:** 70
- **Provider:** immoscout
- **Link:** https://...
- **Active:** yes
- **Created:** 2026-02-25 10:30:00
Markdown is used because it is significantly more token-efficient than JSON (~40-60% fewer tokens for tabular data) and natively understood by all LLMs.
Architecture
┌─────────────────┐ stdio ┌──────────────┐
│ Local LLM │◄──────────────►│ mcp/stdio.js│
│ (LM Studio, │ │ (transport) │
│ Claude, etc.) │ │ │
└─────────────────┘ └──────┬───────┘
│
┌─────────────────┐ Streamable HTTP ┌────┴────────┐
│ Remote LLM │◄───────────────►│ /api/mcp │
│ │ (Bearer token) │ (transport) │
└─────────────────┘ └──────┬───────┘
│
┌──────────┴──────────┐
│ mcpAuthentication │
│ (token validation, │
│ access control) │
└──────────┬──────────┘
│
┌────────┴────────┐
│ mcpAdapter.js │
│ (tool routing │
│ + data fetch) │
└────────┬────────┘
│
┌────────┴────────┐
│ mcpNormalizer.js│
│ (markdown │
│ formatting) │
└────────┬────────┘
│
┌──────┴───────┐
│ Fredy DB │
│ (SQLite) │
└──────────────┘