MCP server providing tools to query and retrieve content from Estéban Soubiran's personal websites including pages, talks, and infrastructure documentation
This MCP server defines 3 tools for querying a blog/content site (soubiran.dev). Tool naming is clear and verb-prefixed (list_, get_, search_). Descriptions are present and moderately detailed. However, parameter schemas lack explicit type definitions in the visible code, and output schemas are not documented. The list_content tool accepts arbitrary JavaScript code, which is unusual and high-risk. Overall structure is sound for a read-only content API, but schema documentation and parameter constraints need improvement.
Retrieve one complete content document by its globally unique ID. Use search_content or list_content to discover an ID.
Query the complete source directories with a read-only async JavaScript arrow function. Available data: type Page = { id: string type: "page" | "post" | "series" | "episode" title: string description?: string language: string slug: string url: string date?: string // ISO date, for posts, series, and episodes translations?: Record<string, { id: string, url: string }> part?: number // episode number series?: { id: string, url: string } // for episodes episodeCount?: number // for series episodes?: { id: string, title: string, url: string, part: number }[] // for series } type Talk = { id: string type: "talk" title: string description?: string date: string // ISO date url: string language: string topics: string[] event: { name: string, url: string, location: { city: string, country: string } } links: { slides: string, source: string, pdf: string, recording?: string, audio?: string, transcript?: string, article?: string } } type Catalog<T> = { schemaVersion: string generatedAt: string // ISO date-time site: { id: string, url: string } data: T[] } type PagesCatalog = Catalog<Page> type TalksCatalog = Catalog<Talk> type EcosystemNode = { type: string id?: string name: string description?: string href?: string ecosystem?: EcosystemNode[] } type InfraPage = { id: string type: string title: string description?: string language: string url: string ecosystem?: EcosystemNode[] links?: unknown } const pages: PagesCatalog const talks: TalksCatalog const infra: Catalog<InfraPage> Current talk topics: [topic list]. Your code must be a single async arrow function and return a JSON-serializable value. The data is recursively frozen. Code has no network, secrets, storage, or Worker bindings.
Search pages, talks, and infra content semantically. Results are ranked excerpts with a category and stable ID suitable for get_content.
Output schemas not documented. LLMs cannot anticipate response structure for get_content and search_content. No documented fields, types, or result limits.
list_content accepts arbitrary JavaScript code execution. This is extremely high-risk and not explicitly constrained. Description mentions 'read-only' but does not explain sandbox limits, available globals, execution timeout, or what happens if code throws.
Parameter constraints missing. The 'id' parameter in get_content should document format (e.g. 'globally unique ID returned by list_content or search_content'). The 'query' parameter in search_content should document length/character limits.
Inferred effective spec: <=2025-11-25.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | C | 63 | <=2025-11-25 | v2 |
| 2026-03-09 | F | 49 | - | v1 |
Pagination not addressed. search_content and list_content likely return variable-length results. No mention of limit, offset, page_size, total_count, or next_cursor in tool descriptions or schemas.
No error handling guidance. Tool descriptions do not explain what happens if an ID is not found, if search returns no results, or if code execution fails. LLMs cannot plan recovery steps.