Skip to main content
Glama
forthy

Effect Q&A MCP Server

by forthy

Effect Q&A MCP Server

A Model Context Protocol (MCP) server that exposes a single tool: get-categories-summary. Fetches category data from a Q&A service API and returns a markdown summary grouped by category.


Quick Start

# Install dependencies
bun install

# Start the MCP server (requires QA_SERVICE_URL)
QA_SERVICE_URL=https://your-qa-api.example.com bun run index.ts

# Run tests
bun run test

# Type-check
npx tsc --noEmit

# Format code
bun run fmt

Related MCP server: MCP Knowledge Base Server

Architecture Overview

Component Diagram

graph TB
    subgraph "MCP Client"
        Client[MCP Client<br/>(Claude, Cursor, etc.)]
    end

    subgraph "MCP Server Process"
        Server[McpServer.layerHttp<br/>:3000/mcp]
        Tool[get-categories-summary<br/>Tool Handler]
        ApiClient[ApiClient Service<br/>fetchCategories]
        HttpClient[NodeHttpClient.layer<br/>Platform HTTP]
    end

    subgraph "External"
        QA_API[Q&A Service API<br/>GET /api/v1/categories]
    end

    Client <-- MCP over HTTP --> Server
    Server --> Tool
    Tool --> ApiClient
    ApiClient --> HttpClient
    HttpClient --> QA_API

Layer Stack (Inner → Outer)

The server is composed as an Effect Layer stack. Each layer provides services to the layers above it.

graph TB
    subgraph "Layer Stack"
        L5[Layer 5: registerTool<br/>Tool Registration]
        L4[Layer 4: ApiClient.Default<br/>Q&A API Client]
        L3[Layer 3: McpServer.layerHttp<br/>MCP Protocol @ /mcp]
        L2[Layer 2: NodeHttpServer.layer<br/>Node HTTP Server]
        L1[Layer 1: NodeHttpClient.layer<br/>Platform HTTP Transport]
    end

    L1 --> L2
    L2 --> L3
    L3 --> L4
    L4 --> L5

    style L1 fill:#f9f,stroke:#333
    style L2 fill:#bbf,stroke:#333
    style L3 fill:#bfb,stroke:#333
    style L4 fill:#ff9,stroke:#333
    style L5 fill:#f96,stroke:#333

Layer

Responsibility

Provides

1. NodeHttpClient.layer

Platform HTTP transport (fetch, connections, pooling)

HttpClient.HttpClient

2. NodeHttpServer.layer

Node.js HTTP server listening on MCP_PORT (default 3000)

HttpServer.HttpServer

3. McpServer.layerHttp

MCP protocol handler at /mcp endpoint

McpServer.McpServer

4. ApiClient.Default

Q&A API client with config (QA_SERVICE_URL, QA_API_KEY)

ApiClient

5. registerTool

Wires get-categories-summary handler to MCP server

— (side effect)


Module Structure

src/
├── index.ts       — MCP server setup, layer composition, entry point
├── api-client.ts  — Effect.Service for Q&A API (errors, HTTP adapter)
├── summary.ts     — Pure function: Category[] → markdown string
├── types.ts       — Effect Schema definitions (Category, CategoriesResponse)
└── services.ts    — Reserved for future top-level services
test/
├── index.test.ts      — buildSummary tests + handler with nock
└── summary.test.ts    — buildSummary edge cases

Data Flow

sequenceDiagram
    participant Client as MCP Client
    participant Server as MCP Server
    participant Tool as get-categories-summary
    participant ApiClient as ApiClient
    participant HttpClient as HttpClient
    participant QA as Q&A API

    Client->>Server: POST /mcp {method: "tools/call", params: {name: "get-categories-summary"}}
    Server->>Tool: invoke handler
    Tool->>ApiClient: fetchCategories()
    ApiClient->>HttpClient: execute GET /api/v1/categories
    HttpClient->>QA: HTTP Request
    QA-->>HttpClient: 200 OK {data: [...]}
    HttpClient-->>ApiClient: HttpClientResponse
    ApiClient->>ApiClient: filterStatusOk → decode JSON → Schema.decode
    ApiClient-->>Tool: CategoriesResponse
    Tool->>Tool: buildSummary(categories.data)
    Tool-->>Server: CallToolResult {content: [TextContent]}
    Server-->>Client: MCP Response

Configuration

Environment Variable

Required

Description

QA_SERVICE_URL

Yes

Base URL of Q&A API (e.g., https://qa.example.com)

QA_API_KEY

No

Bearer token for authenticated requests

MCP_PORT

No

HTTP listen port (default: 3000)


Error Handling

The tool handler folds all errors into CallToolResult with isError: true:

Error Type

Trigger

User-Facing Message

HttpError

Non-2xx HTTP status

Error fetching categories: HTTP <status>

DecodeError

Schema validation failed

Error fetching categories: unexpected response format — <details>

UnknownError

Transport/DNS/timeout/JSON parse

Error fetching categories: <message>


Tool Specification

get-categories-summary

  • Description: Fetches categories from the Q&A service and returns a narrative summary grouped by category

  • Input: None (empty object)

  • Annotations: readOnlyHint: true — clients may cache/replay

  • Output: Markdown string via TextContent

Example Output:

Found 3 categories across 2 groups.

## bugs (2)

- **Login Issue**: Cannot log in
- **Crash**: App crashes on start

## features (1)

- **Dark Mode**: Add dark theme

Testing

# Unit tests (pure functions)
bun run test

# With coverage
bun run test:coverage

Test strategy:

  • buildSummary — pure function tests (empty, single, multi-category)

  • Handler — integration test with nock intercepting HTTP to QA_SERVICE_URL


Development

# Format check
bun run fmt:check

# Type-check
npx tsc --noEmit

# Regenerate docs
bun run docs

Dependencies

Runtime

  • @effect/ai — MCP server implementation

  • @effect/platform-node — Node.js platform layers (HTTP client/server)

  • effect — Core Effect-TS (services, layers, schemas, errors)

Dev

  • @effect/vitest — Effect-native testing (it.effect, assert)

  • nock — HTTP mocking for integration tests

  • oxfmt — Formatter (printWidth 120, no semicolons)

  • @effect/language-service — IDE support via tsconfig plugin


License

Private — internal tooling.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Wraps the StackExchange API v2.3 to enable reading StackExchange data (questions, answers, etc.) without authentication. Allows AI agents to query StackExchange content through natural language or direct tool calls.
    3 npm
    1
    MIT