MCP Service
The Geek Haus MCP server exposes our curated feed to AI assistants over Model Context Protocol. Any client that speaks Streamable HTTP MCP can connect, no install required.
Endpoint
https://geekhaus.club/api/mcp- ▸Transport: Streamable HTTP (POST). SSE is not supported (deprecated by the spec).
- ▸Protocol version:
2025-06-18. - ▸Session model: stateless. No
Mcp-Session-Idis required between calls — every request is independent.
Authentication
The same Partner API key authenticates MCP requests. Send it as a Bearer token in the Authorization header. To get a key, contact us.
Connecting a client
Most modern MCP clients (Claude Desktop, Cursor, Windsurf, ChatGPT custom connectors) accept a JSON config like this:
{
"mcpServers": {
"geekhaus": {
"url": "https://geekhaus.club/api/mcp",
"headers": {
"Authorization": "Bearer YOUR_API_KEY"
}
}
}
}For stdio-only clients, wrap with mcp-remote:
{
"mcpServers": {
"geekhaus": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://geekhaus.club/api/mcp",
"--header",
"Authorization: Bearer YOUR_API_KEY"
]
}
}
}Where each client expects this config
| Client | Config location |
|---|---|
| Claude Desktop | macOS: ~/Library/Application Support/Claude/claude_desktop_config.json · Windows: %APPDATA%\Claude\claude_desktop_config.json |
| Cursor | ~/.cursor/mcp.json (global) or .cursor/mcp.json (per-project) |
| Windsurf | ~/.codeium/windsurf/mcp_config.json |
| ChatGPT custom connectors | Settings → Connectors → Add MCP server (paste URL + Bearer key in UI) |
After editing the config, restart the client. The tools show up in the client's tool picker — try a prompt like "Use geekhaus to show me the top tech stories this week" to confirm the wiring works.
Available tools
| Tool | Purpose |
|---|---|
search_articles | Browse articles with optional filters (source slug, since, limit, cursor). |
get_article | Fetch one article by slug. |
list_sources | List every publication tracked, with article counts. |
get_weekly_digest | Top recent articles within a days window (default 7 days, 7 items). |
All tools accept an optional locale argument (en or ko, default en).
Argument schemas
search_articles
| Arg | Type | Required | Default | Notes |
|---|---|---|---|---|
locale | 'en' | 'ko' | no | 'en' | |
source | string | no | — | Source slug (see list_sources). |
since | ISO-8601 datetime | no | — | Lower bound. |
limit | integer 1-100 | no | 20 | |
cursor | string | no | — | Opaque cursor from previous response. |
get_article
| Arg | Type | Required | Default |
|---|---|---|---|
slug | string | yes | — |
locale | 'en' | 'ko' | no | 'en' |
list_sources
| Arg | Type | Required | Default |
|---|---|---|---|
locale | 'en' | 'ko' | no | 'en' |
get_weekly_digest
| Arg | Type | Required | Default |
|---|---|---|---|
locale | 'en' | 'ko' | no | 'en' |
days | integer 1-90 | no | 7 |
limit | integer 1-50 | no | 7 |
Tool results return as { content: [{ type: "text", text: "<json>" }] }. The text field is the JSON-stringified response from the matching REST endpoint, so all Partner API field semantics apply.
Low-level protocol examples
Every MCP call is a JSON-RPC 2.0 POST. The server responds with Content-Type: text/event-stream containing one data: line per JSON-RPC message. Parse the line after data: as JSON to get the actual response.
Initialize
Request:
curl -X POST https://geekhaus.club/api/mcp \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
--data '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"capabilities": {},
"clientInfo": { "name": "my-app", "version": "1.0.0" }
}
}'Response (SSE frame body):
event: message
data: {"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2025-06-18","capabilities":{"tools":{"listChanged":true}},"serverInfo":{"name":"geekhaus-mcp","version":"1.0.0"}}}tools/list
Request:
curl -X POST https://geekhaus.club/api/mcp \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
--data '{ "jsonrpc": "2.0", "id": 2, "method": "tools/list" }'Response (truncated):
{
"jsonrpc": "2.0",
"id": 2,
"result": {
"tools": [
{ "name": "search_articles", "title": "Search articles", "description": "..." },
{ "name": "get_article", "title": "Get article", "description": "..." },
{ "name": "list_sources", "title": "List sources", "description": "..." },
{ "name": "get_weekly_digest", "title": "Get weekly digest", "description": "..." }
]
}
}tools/call — search_articles
Request:
curl -X POST https://geekhaus.club/api/mcp \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
--data '{
"jsonrpc": "2.0",
"id": 3,
"method": "tools/call",
"params": {
"name": "search_articles",
"arguments": { "source": "anthropic-com", "limit": 2 }
}
}'Response:
{
"jsonrpc": "2.0",
"id": 3,
"result": {
"content": [
{
"type": "text",
"text": "{\"items\":[{\"id\":\"...\",\"slug\":\"2026/05/22/...\",\"title\":\"...\",\"summary\":\"...\"}],\"nextCursor\":\"2026-05-22T...\"}"
}
]
}
}The text field is a JSON-stringified /api/v1/articles response. Parse it with JSON.parse(result.content[0].text).
Client SDK example (TypeScript)
Using @modelcontextprotocol/sdk:
import { Client } from '@modelcontextprotocol/sdk/client/index.js'
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js'
const transport = new StreamableHTTPClientTransport(new URL('https://geekhaus.club/api/mcp'), {
requestInit: {
headers: { Authorization: 'Bearer YOUR_API_KEY' },
},
})
const client = new Client({ name: 'my-app', version: '1.0.0' })
await client.connect(transport)
const tools = await client.listTools()
console.log(tools.tools.map((t) => t.name))
const result = await client.callTool({
name: 'get_weekly_digest',
arguments: { days: 7, limit: 5 },
})
const payload = JSON.parse(result.content[0].text)
console.log(payload.items.length, 'articles in the last 7 days')Client SDK example (Python)
Using mcp (the official Python SDK):
import asyncio
from mcp.client.session import ClientSession
from mcp.client.streamable_http import streamablehttp_client
URL = "https://geekhaus.club/api/mcp"
HEADERS = {"Authorization": "Bearer YOUR_API_KEY"}
async def main():
async with streamablehttp_client(URL, headers=HEADERS) as (read, write, _):
async with ClientSession(read, write) as session:
await session.initialize()
tools = await session.list_tools()
print([t.name for t in tools.tools])
result = await session.call_tool(
"search_articles", {"source": "anthropic-com", "limit": 3}
)
import json
payload = json.loads(result.content[0].text)
print(len(payload["items"]), "articles from anthropic.com")
asyncio.run(main())Errors
Missing or invalid keys return 401 with the standard envelope:
{ "error": { "code": "unauthorized", "message": "Missing API key." } }Tool-level errors propagate inside the JSON-RPC error field per spec.
Notes
- ▸The MCP server and Partner API share the same data layer and editorial filtering. Whatever you see through REST, you will see through MCP.
- ▸Tool results are returned as JSON-stringified text. Most clients pass this straight to the model without further parsing.
- ▸Reach out via contact for access, feedback, or to request a new tool.