docs: add agent guidelines, architecture specs, and decision records
- Add AGENTS.md defining coding standards, security, and workflows - Add GEMINI.md and CLAUDE.md referencing AGENTS.md - Add docs/ARCHITECTURE.md detailing MCP server design and OpenProject API integration - Add docs/DECISIONS.md with initial ADRs (stack, transport, auth, scoping) - Add .gitignore for Node.js and secrets protection
This commit is contained in:
+30
@@ -0,0 +1,30 @@
|
||||
# Dependencies
|
||||
node_modules/
|
||||
.pnpm-store/
|
||||
|
||||
# Build artifacts
|
||||
dist/
|
||||
build/
|
||||
coverage/
|
||||
|
||||
# Environment variables & secrets
|
||||
.env
|
||||
.env.*
|
||||
!.env.example
|
||||
|
||||
# IDE & Editor files
|
||||
.idea/
|
||||
.vscode/
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# OS files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
@@ -0,0 +1,79 @@
|
||||
# Agent Guidelines for openproject-mcp
|
||||
|
||||
Welcome to the `openproject-mcp` project. This document defines operating principles, architectural conventions, coding practices, and workflow expectations for AI agents collaborating on this codebase.
|
||||
|
||||
## 1. Project Overview
|
||||
|
||||
`openproject-mcp` is a Model Context Protocol (MCP) server that acts as an intelligent bridge to [OpenProject](https://github.com/opf/openproject). It enables LLM agents and clients (e.g., Claude Desktop, Antigravity, Cursor) to browse, query, and interact with OpenProject instances using user API keys via OpenProject's REST API v3.
|
||||
|
||||
### Primary Objectives
|
||||
- Expose OpenProject projects, work packages, queries, users, and taxonomies as MCP tools and resources.
|
||||
- Provide secure, transparent authentication via OpenProject API tokens.
|
||||
- Handle OpenProject's HAL+JSON schema and complex query filter syntax gracefully.
|
||||
- Ensure lightweight, resilient runtime execution over standard MCP transports (stdio).
|
||||
|
||||
---
|
||||
|
||||
## 2. General Principles for Agents
|
||||
|
||||
1. **Check Documentation First**: Before proposing or executing architectural changes, consult [docs/ARCHITECTURE.md](file:///home/user/openproject-mcp/docs/ARCHITECTURE.md) and [docs/DECISIONS.md](file:///home/user/openproject-mcp/docs/DECISIONS.md).
|
||||
2. **Document Architectural Decisions**: If a change alters the design, dependencies, or interfaces, record a new entry or update existing records in [docs/DECISIONS.md](file:///home/user/openproject-mcp/docs/DECISIONS.md).
|
||||
3. **Preserve Repository Integrity**: Do not delete existing comments, licenses, or configuration files unless specifically tasked with refactoring them.
|
||||
4. **Security by Design**: Never log or commit credentials, API tokens, or session secrets.
|
||||
|
||||
---
|
||||
|
||||
## 3. Technology Stack & Coding Standards
|
||||
|
||||
### Stack
|
||||
- **Language**: TypeScript (targeting ES2022 / Node.js >= 18).
|
||||
- **MCP Framework**: Official `@modelcontextprotocol/sdk`.
|
||||
- **Validation**: `zod` for input schema validation and TypeScript inference.
|
||||
- **HTTP Client**: Native `fetch` or a minimal strongly-typed wrapper (e.g., `undici` or `axios` if required for streaming/interceptors).
|
||||
- **Testing**: Vitest or Jest with fixture-based mocking for HAL+JSON API responses.
|
||||
|
||||
### Code Style
|
||||
- **TypeScript**: Strict type checking enabled (`strict: true` in `tsconfig.json`). Avoid `any` - use `unknown` with type guards or explicit Zod schemas.
|
||||
- **Modularity**: Separate transport/MCP protocol concerns from OpenProject domain logic and HTTP client handling.
|
||||
- **Naming Conventions**:
|
||||
- Files and directories: `kebab-case` (e.g., `openproject-client.ts`, `work-packages.ts`).
|
||||
- Types and Interfaces: `PascalCase` (e.g., `OpenProjectConfig`, `WorkPackageResource`).
|
||||
- Functions and variables: `camelCase` (e.g., `fetchWorkPackage`, `projectIdentifier`).
|
||||
- Constants: `UPPER_SNAKE_CASE` (e.g., `DEFAULT_PAGE_SIZE`, `API_V3_PREFIX`).
|
||||
- MCP Tool Names: `snake_case` prefixed with domain (e.g., `openproject_list_projects`, `openproject_get_work_package`).
|
||||
|
||||
---
|
||||
|
||||
## 4. OpenProject API Integration Guidelines
|
||||
|
||||
### Authentication
|
||||
- OpenProject REST API v3 uses HTTP Basic Authentication for API keys:
|
||||
- Username: `apikey`
|
||||
- Password: `<USER_API_KEY>`
|
||||
- Header format: `Authorization: Basic base64(apikey:<USER_API_KEY>)`
|
||||
- Base URL format: `<protocol>://<host>[:port]` (e.g., `https://openproject.example.com`). The API v3 root is at `/api/v3`.
|
||||
|
||||
### HAL+JSON Format
|
||||
- OpenProject responses use HAL+JSON format (`_links`, `_embedded`).
|
||||
- Agents must ensure parsing utilities extract canonical identifiers and friendly representations for LLM consumption rather than dumping raw deep HAL trees when not needed.
|
||||
|
||||
### Filters and Pagination
|
||||
- OpenProject API v3 filters use JSON string parameters (e.g., `filters=[{"status_id":{"operator":"o","values":[]}}]`).
|
||||
- Tool handlers should accept clean, human/LLM-friendly arguments (e.g., `status: "open"`, `projectId: 12`) and translate them into OpenProject's filter syntax.
|
||||
|
||||
---
|
||||
|
||||
## 5. Security & Safety
|
||||
|
||||
- **Secrets Management**: Read `OPENPROJECT_BASE_URL` and `OPENPROJECT_API_KEY` from environment variables. Never hardcode credentials in tests, scripts, or examples.
|
||||
- **Input Validation**: All tool parameters must be validated via Zod schemas before being used in HTTP requests.
|
||||
- **Safe Error Propagation**: Sanitize error messages returned to the MCP client. Never leak authorization headers or system paths in tool error responses.
|
||||
|
||||
---
|
||||
|
||||
## 6. Development Workflow for Agents
|
||||
|
||||
1. **Understand Task Scope**: Read requirements and check existing code and docs.
|
||||
2. **Test-Driven or Verification-Driven**: When writing or updating tools, verify against mock OpenProject API responses.
|
||||
3. **Update Docs**: Keep `docs/ARCHITECTURE.md` and `docs/DECISIONS.md` synchronized with the actual codebase.
|
||||
4. **Clean Commits**: Make focused, atomic commits with descriptive messages following Conventional Commits (e.g., `feat:`, `fix:`, `docs:`, `refactor:`).
|
||||
@@ -0,0 +1,5 @@
|
||||
# Claude Instructions for openproject-mcp
|
||||
|
||||
Please refer to [AGENTS.md](./AGENTS.md) for all project guidelines, coding conventions, architectural standards, and workflow instructions.
|
||||
|
||||
All agents and assistants operating in this repository must follow the instructions defined in `AGENTS.md`.
|
||||
@@ -0,0 +1,5 @@
|
||||
# Gemini Instructions for openproject-mcp
|
||||
|
||||
Please refer to [AGENTS.md](./AGENTS.md) for all project guidelines, coding conventions, architectural standards, and workflow instructions.
|
||||
|
||||
All agents and assistants operating in this repository must follow the instructions defined in `AGENTS.md`.
|
||||
@@ -0,0 +1,172 @@
|
||||
# Architecture Documentation: openproject-mcp
|
||||
|
||||
## 1. System Overview
|
||||
|
||||
`openproject-mcp` is a Model Context Protocol (MCP) server providing LLM applications (Claude Desktop, Cursor, Antigravity, etc.) with structured access to an OpenProject instance. The server interfaces with OpenProject's REST API v3 using personal API keys, exposing tools and resources for browsing and querying projects, work packages, custom queries, taxonomies, and users.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph Client ["MCP Client"]
|
||||
Agent["LLM Agent / Assistant"]
|
||||
end
|
||||
|
||||
subgraph Server ["openproject-mcp Server"]
|
||||
Transport["Stdio Transport"]
|
||||
Router["Tool & Resource Router"]
|
||||
|
||||
subgraph DomainServices ["Domain Services"]
|
||||
ProjSvc["Projects Service"]
|
||||
WpSvc["Work Packages Service"]
|
||||
QuerySvc["Queries Service"]
|
||||
MetaSvc["Metadata & Taxonomies"]
|
||||
end
|
||||
|
||||
ClientCore["OpenProject API Client"]
|
||||
AuthHandler["Auth & Request Builder\n(Basic Auth: apikey:<token>)"]
|
||||
HalParser["HAL+JSON Parser & Normalizer"]
|
||||
end
|
||||
|
||||
subgraph Remote ["OpenProject Instance"]
|
||||
ApiV3["REST API v3 (/api/v3)"]
|
||||
end
|
||||
|
||||
Agent <-->|MCP JSON-RPC (stdio)| Transport
|
||||
Transport <--> Router
|
||||
Router --> DomainServices
|
||||
DomainServices --> ClientCore
|
||||
ClientCore --> AuthHandler
|
||||
ClientCore --> HalParser
|
||||
AuthHandler -->|HTTPS Requests| ApiV3
|
||||
ApiV3 -->|HAL+JSON Responses| HalParser
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. Core Architectural Layers
|
||||
|
||||
The system is organized into four modular layers:
|
||||
|
||||
### 2.1. MCP Server & Transport Layer
|
||||
- **Responsibility**: Manages the MCP connection lifecycle, tool definitions, input validation, and JSON-RPC dispatching.
|
||||
- **Protocol**: MCP specification implemented via `@modelcontextprotocol/sdk`.
|
||||
- **Default Transport**: `StdioServerTransport` for local integration with desktop clients and CLI tools.
|
||||
- **Schema Validation**: Each tool declares its arguments using Zod schemas, automatically generating standard JSON Schema definitions for the LLM.
|
||||
|
||||
### 2.2. Domain Services / Tool Providers
|
||||
Domain services map MCP tool calls to concrete business logic and OpenProject API operations:
|
||||
- **Projects Service**: Listing accessible projects, retrieving project details, and fetching project-level schemas.
|
||||
- **Work Packages Service**: Listing work packages with filters, searching by text or ID, retrieving work package details, and inspecting relations.
|
||||
- **Queries Service**: Listing saved queries (views) configured in OpenProject and executing them.
|
||||
- **Metadata & Taxonomies Service**: Retrieving statuses, work package types, priorities, categories, versions, and users to enable LLMs to construct valid queries and interpret responses.
|
||||
|
||||
### 2.3. OpenProject Client Layer
|
||||
- **HTTP Transport**: Handles HTTPS communication against the configured `OPENPROJECT_BASE_URL`.
|
||||
- **Authentication Handler**: Enforces OpenProject API v3 authentication by injecting `Authorization: Basic base64(apikey:<api_key>)` headers.
|
||||
- **HAL+JSON Parser**: OpenProject API v3 represents entities using HAL+JSON format (`_links`, `_embedded`). The parser unwraps links, extracts embedded entities, and converts them into clean, token-efficient JSON structures for LLM consumption.
|
||||
- **Query Filter Builder**: Serializes user-friendly filtering parameters into OpenProject's JSON-based filter query syntax (e.g. `filters=[{"status_id":{"operator":"o","values":[]}}]`).
|
||||
- **Error Normalizer**: Intercepts HTTP 4xx/5xx responses and maps them to descriptive MCP tool errors without exposing sensitive credential data.
|
||||
|
||||
### 2.4. Configuration & Environment Layer
|
||||
- Parses and validates configuration at startup:
|
||||
- `OPENPROJECT_BASE_URL`: Base URL of the OpenProject instance (e.g., `https://openproject.example.com`).
|
||||
- `OPENPROJECT_API_KEY`: User API key generated in OpenProject under "My Account > Access tokens".
|
||||
- Fails fast with actionable setup advice if required credentials are missing or invalid.
|
||||
|
||||
---
|
||||
|
||||
## 3. Tool Specifications (Browse & Query Scope)
|
||||
|
||||
| MCP Tool Name | Description | Key Parameters |
|
||||
| :--- | :--- | :--- |
|
||||
| `openproject_list_projects` | List projects accessible to the authenticated user | `pageSize`, `offset`, `sortBy` |
|
||||
| `openproject_get_project` | Get details of a single project by ID or identifier | `projectId` (number or string identifier) |
|
||||
| `openproject_list_work_packages` | Browse work packages with filtering and pagination | `projectId`, `status`, `type`, `pageSize`, `offset`, `filters` |
|
||||
| `openproject_get_work_package` | Get full details of a specific work package | `workPackageId` (number) |
|
||||
| `openproject_list_queries` | List saved project or global queries (views) | `projectId`, `pageSize`, `offset` |
|
||||
| `openproject_get_query` | Retrieve details and results of a saved query | `queryId` (number) |
|
||||
| `openproject_list_types` | List all available work package types (Task, Bug, Milestone, etc.) | None |
|
||||
| `openproject_list_statuses` | List all available work package statuses (New, In Progress, Closed, etc.) | None |
|
||||
| `openproject_list_priorities` | List all priority levels | None |
|
||||
| `openproject_list_users` | List users in the OpenProject instance | `pageSize`, `offset` |
|
||||
|
||||
---
|
||||
|
||||
## 4. OpenProject API v3 Specifics
|
||||
|
||||
### 4.1. Authentication Details
|
||||
OpenProject API v3 utilizes HTTP Basic Authentication for API tokens:
|
||||
```http
|
||||
GET /api/v3/projects HTTP/1.1
|
||||
Host: openproject.example.com
|
||||
Authorization: Basic YXBpa2V5OnlvdXItb3BlbnByb2plY3QtYXBpLWtleQ==
|
||||
Accept: application/hal+json
|
||||
```
|
||||
Where `YXBpa2V5OnlvdXItb3BlbnByb2plY3QtYXBpLWtleQ==` is the Base64 encoding of `apikey:<your-api-key>`.
|
||||
|
||||
### 4.2. HAL+JSON Handling
|
||||
API responses contain `_links` linking to related resources (parent project, author, assignee, status, type). The client layer normalizes these into human-readable labels and numeric IDs so the LLM agent can reason over them easily.
|
||||
|
||||
### 4.3. Filter Syntax Translation
|
||||
OpenProject filters are passed via a URL-encoded JSON string array. Example:
|
||||
```json
|
||||
[
|
||||
{ "status_id": { "operator": "o", "values": [] } },
|
||||
{ "project": { "operator": "=", "values": ["12"] } }
|
||||
]
|
||||
```
|
||||
The client layer provides helper builders so tools can accept friendly parameters (e.g. `{ onlyOpen: true, projectId: 12 }`) and translate them automatically into the required format.
|
||||
|
||||
---
|
||||
|
||||
## 5. Security & Isolation
|
||||
|
||||
1. **Token Protection**: Credentials are read from environment variables or standard config files. Tokens are never echoed in logs or responses.
|
||||
2. **Permission Boundary**: The MCP server operates with the exact permission scope of the provided API key. No elevated access is granted beyond what the user possesses in OpenProject.
|
||||
3. **Input Sanitization**: All arguments from the LLM are validated via Zod schemas prior to making network requests, preventing request-smuggling or path traversal.
|
||||
4. **Transport Isolation**: The default stdio transport communicates only through standard input/output with the host client process, with no exposed network ports.
|
||||
|
||||
---
|
||||
|
||||
## 6. Project Directory Structure
|
||||
|
||||
```
|
||||
openproject-mcp/
|
||||
├── docs/
|
||||
│ ├── ARCHITECTURE.md # System architecture and specifications
|
||||
│ └── DECISIONS.md # Architecture Decision Records (ADR)
|
||||
├── src/
|
||||
│ ├── index.ts # CLI entry point and startup
|
||||
│ ├── server.ts # MCP server instance & tool registration
|
||||
│ ├── client/
|
||||
│ │ ├── api-client.ts # OpenProject REST API v3 HTTP client
|
||||
│ │ ├── hal-parser.ts # HAL+JSON parsing and transformation
|
||||
│ │ ├── filter-builder.ts # OpenProject JSON filter builder
|
||||
│ │ └── types.ts # OpenProject API type definitions
|
||||
│ ├── config/
|
||||
│ │ └── index.ts # Configuration loader and Zod schema
|
||||
│ ├── services/
|
||||
│ │ ├── projects.ts # Projects domain service
|
||||
│ │ ├── work-packages.ts # Work packages domain service
|
||||
│ │ ├── queries.ts # Queries domain service
|
||||
│ │ └── metadata.ts # Types, statuses, priorities, users
|
||||
│ └── tools/
|
||||
│ ├── project-tools.ts # MCP tool definitions for projects
|
||||
│ ├── work-package-tools.ts# MCP tool definitions for work packages
|
||||
│ └── metadata-tools.ts # MCP tool definitions for metadata
|
||||
├── tests/
|
||||
│ ├── fixtures/ # HAL+JSON mock fixtures
|
||||
│ ├── client.test.ts # OpenProject client unit tests
|
||||
│ └── tools.test.ts # MCP tool integration tests
|
||||
├── AGENTS.md # Operating guidelines for AI agents
|
||||
├── package.json # Project dependencies and scripts
|
||||
└── tsconfig.json # TypeScript compiler configuration
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Future Roadmap
|
||||
|
||||
- **Phase 1 (Current)**: Read/browse capability for projects, work packages, queries, and taxonomies.
|
||||
- **Phase 2**: Mutating operations (create/update work packages, add comments, log time).
|
||||
- **Phase 3**: Attachment inspection and download resources.
|
||||
- **Phase 4**: SSE / Stream transport for remote server deployments and multi-user environments.
|
||||
@@ -0,0 +1,185 @@
|
||||
# Architecture Decision Records (ADR)
|
||||
|
||||
This document records the key architectural and technical decisions made for `openproject-mcp`.
|
||||
|
||||
---
|
||||
|
||||
## ADR-001: Technology Stack Selection (TypeScript & Node.js)
|
||||
|
||||
### Status
|
||||
Accepted
|
||||
|
||||
### Context
|
||||
We need to build a companion MCP server for OpenProject (https://github.com/opf/openproject) that runs reliably on local machines and integrates smoothly with MCP clients such as Claude Desktop, Cursor, and Antigravity.
|
||||
|
||||
Key candidate ecosystems:
|
||||
1. **TypeScript / Node.js**: Official `@modelcontextprotocol/sdk`, high community adoption, direct JSON handling, first-class typings, fast startup time.
|
||||
2. **Python**: Python `mcp` SDK, strong for data science, but packaging CLI binaries or distributed environments across non-Python users requires pyinstaller or pipx.
|
||||
|
||||
### Decision
|
||||
Choose **TypeScript** running on **Node.js** (>= 18) with the official `@modelcontextprotocol/sdk`.
|
||||
|
||||
### Consequences
|
||||
- **Positive**:
|
||||
- Leverages the most mature and widely-maintained MCP SDK implementation.
|
||||
- Native JSON and HAL+JSON data manipulation with strict typing.
|
||||
- Simple execution via `npx` or standard Node runner.
|
||||
- Excellent developer tooling and linting with TypeScript and ESLint.
|
||||
- **Negative**:
|
||||
- Requires Node.js runtime on the host environment.
|
||||
|
||||
---
|
||||
|
||||
## ADR-002: Default Transport Protocol (Stdio Transport)
|
||||
|
||||
### Status
|
||||
Accepted
|
||||
|
||||
### Context
|
||||
The Model Context Protocol supports multiple communication transports: Standard I/O (`stdio`), Server-Sent Events (`SSE`), and HTTP. Local AI desktop tools (Claude Desktop, Cursor, local agent runners) primarily spawn MCP servers as child processes communicating over `stdin` and `stdout`.
|
||||
|
||||
### Decision
|
||||
Implement **`StdioServerTransport`** as the default primary transport layer. Structure the MCP server initialization modularly so SSE / HTTP transports can be introduced later without refactoring domain logic.
|
||||
|
||||
### Consequences
|
||||
- **Positive**:
|
||||
- Out-of-the-box compatibility with Claude Desktop and command-line LLM runners.
|
||||
- Zero network port binding conflicts or local firewall prompts.
|
||||
- Lifecycle is tied directly to the parent LLM process.
|
||||
- **Negative**:
|
||||
- Logging must be strictly routed to `stderr` rather than `stdout`, as any arbitrary write to `stdout` corrupts the MCP JSON-RPC protocol stream.
|
||||
|
||||
---
|
||||
|
||||
## ADR-003: Direct Integration with OpenProject REST API v3
|
||||
|
||||
### Status
|
||||
Accepted
|
||||
|
||||
### Context
|
||||
OpenProject provides a comprehensive REST API v3 located at `/api/v3`. It uses HAL+JSON format and provides endpoints for projects, work packages, queries, types, statuses, users, and more.
|
||||
|
||||
### Decision
|
||||
Directly integrate with OpenProject's native **REST API v3** using a lightweight HTTP client rather than relying on unmaintained third-party wrapper libraries.
|
||||
|
||||
### Consequences
|
||||
- **Positive**:
|
||||
- Full compatibility with current and future OpenProject versions (12.x, 13.x, 14.x+).
|
||||
- No external library obsolescence risks.
|
||||
- Accurate mapping to OpenProject's official schema and capabilities.
|
||||
- **Negative**:
|
||||
- We must implement and maintain custom HAL+JSON deserialization and filter encoding helpers.
|
||||
|
||||
---
|
||||
|
||||
## ADR-004: Authentication Strategy (API Key via HTTP Basic Auth)
|
||||
|
||||
### Status
|
||||
Accepted
|
||||
|
||||
### Context
|
||||
OpenProject REST API v3 supports multiple authentication mechanisms:
|
||||
1. **API Key Authentication**: HTTP Basic Auth with fixed username `apikey` and the user's personal API token as the password (`Authorization: Basic base64(apikey:<api_key>)`).
|
||||
2. **OAuth2**: Requires callback redirect servers and token refresh infrastructure.
|
||||
3. **Session Cookie**: Unsuited for programmatic/MCP server access.
|
||||
|
||||
### Decision
|
||||
Use **Personal API Key authentication via HTTP Basic Auth**. The API key and OpenProject base URL will be configured via environment variables (`OPENPROJECT_BASE_URL` and `OPENPROJECT_API_KEY`) or command-line parameters.
|
||||
|
||||
### Consequences
|
||||
- **Positive**:
|
||||
- Zero interactive login friction: users generate a token once in OpenProject (`My Account > Access tokens`) and supply it.
|
||||
- Stateless and lightweight: no complex token refresh or OAuth flow required.
|
||||
- Operates strictly within the user's personal permissions.
|
||||
- **Negative**:
|
||||
- If an API key is revoked or rotated in OpenProject, the environment variable must be updated.
|
||||
|
||||
---
|
||||
|
||||
## ADR-005: Read/Browse-First Phased Capability Delivery
|
||||
|
||||
### Status
|
||||
Accepted
|
||||
|
||||
### Context
|
||||
Users need to explore, inspect, and query their OpenProject workspace (projects, work packages, backlog items, statuses, queries) through LLMs. Introducing mutating operations (updating work packages, deleting items) early increases risk of unintended changes before browsing and schema representation are proven solid.
|
||||
|
||||
### Decision
|
||||
Phase development with **Read/Browse-First scope**:
|
||||
1. **Phase 1 (Browsing & Discovery)**: Read projects, work packages, saved queries, and taxonomy metadata (types, statuses, priorities, users).
|
||||
2. **Phase 2 (Mutations & Authoring)**: Create/update work packages, add comments, log time entries.
|
||||
3. **Phase 3 (Attachments & Resources)**: Inspect attachments and read wiki/documents.
|
||||
|
||||
### Consequences
|
||||
- **Positive**:
|
||||
- Rapid delivery of high-value, safe tools for LLM reasoning and status summarization.
|
||||
- Minimizes risk of accidental writes during early adoption.
|
||||
- Establishes solid schemas and testing foundations for entities before building mutation actions.
|
||||
- **Negative**:
|
||||
- Write capabilities are deferred to Phase 2.
|
||||
|
||||
---
|
||||
|
||||
## ADR-006: Zod for Input Schema Validation and Type Safety
|
||||
|
||||
### Status
|
||||
Accepted
|
||||
|
||||
### Context
|
||||
MCP tools require strict parameter schemas defined as JSON Schema for LLM function calling. We also need compile-time TypeScript types corresponding to these parameters.
|
||||
|
||||
### Decision
|
||||
Use **Zod** to declare tool argument schemas. Use `@modelcontextprotocol/sdk` utilities (or Zod's JSON schema conversion) to generate the tool input schemas and infer TypeScript parameter types (`z.infer<typeof Schema>`).
|
||||
|
||||
### Consequences
|
||||
- **Positive**:
|
||||
- Single source of truth for runtime validation and static TypeScript types.
|
||||
- Automatic error responses with detailed validation feedback if an LLM generates malformed inputs.
|
||||
- Cleaner tool definitions without manual JSON Schema writing.
|
||||
- **Negative**:
|
||||
- Adds `zod` as a core runtime dependency (standard in TypeScript MCP servers).
|
||||
|
||||
---
|
||||
|
||||
## ADR-007: HAL+JSON Normalization for Token Efficiency
|
||||
|
||||
### Status
|
||||
Accepted
|
||||
|
||||
### Context
|
||||
OpenProject's HAL+JSON responses are deeply nested, containing verbose `_links` objects (self, schema, custom fields, update/delete action links) and metadata. Passing raw HAL+JSON directly to LLMs wastes token context and degrades reasoning performance.
|
||||
|
||||
### Decision
|
||||
Implement a dedicated **HAL Normalizer** (`hal-parser.ts`) that extracts essential entity attributes, resolves human-readable titles/names from linked objects (such as status, priority, author, project), and produces concise, clean JSON payloads for the LLM.
|
||||
|
||||
### Consequences
|
||||
- **Positive**:
|
||||
- Significant reduction in LLM token consumption (up to 60-80% fewer tokens per work package).
|
||||
- Clearer, unambiguous structures for LLMs to reason over and summarize.
|
||||
- Isolation of OpenProject HAL conventions to the client layer.
|
||||
- **Negative**:
|
||||
- Requires maintaining the mapping logic as new entity fields are supported.
|
||||
|
||||
---
|
||||
|
||||
## ADR-008: Testing Strategy with Fixture-Driven HAL Payloads
|
||||
|
||||
### Status
|
||||
Accepted
|
||||
|
||||
### Context
|
||||
Testing against a live OpenProject instance in CI/CD is impractical due to setup complexity and network dependency. Unit and integration tests must run fast and reliably offline.
|
||||
|
||||
### Decision
|
||||
Adopt a **fixture-driven test strategy**:
|
||||
1. Capture representative HAL+JSON payloads from OpenProject API v3 (projects, work packages, queries, schema, error payloads) as JSON fixture files in `tests/fixtures/`.
|
||||
2. Mock HTTP responses using MSW (Mock Service Worker) or Node's `undici` / `fetch` mock utilities.
|
||||
3. Verify MCP tool registration, schema parsing, and client transformation against these fixtures.
|
||||
|
||||
### Consequences
|
||||
- **Positive**:
|
||||
- Fast, completely offline, deterministic test suite.
|
||||
- Tests reflect real-world OpenProject API responses.
|
||||
- Safe regression detection when updating normalizers or tool handlers.
|
||||
- **Negative**:
|
||||
- Fixtures must be periodically verified when targeting major new OpenProject versions.
|
||||
Reference in New Issue
Block a user