From 8c096a9dc85cec7ec8f91724e45c1295d367f63c Mon Sep 17 00:00:00 2001 From: Frantisek Pac Date: Mon, 23 Feb 2026 17:11:32 +0100 Subject: [PATCH 1/2] feat: add agent context files --- AGENTS.md | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ CLAUDE.md | 1 + 2 files changed, 66 insertions(+) create mode 100644 AGENTS.md create mode 100644 CLAUDE.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..1bad53d --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,65 @@ +# make-mcp-server + +TypeScript MCP (Model Context Protocol) server that exposes Make.com on-demand scenarios as callable tools for AI assistants. Uses stdio transport (no HTTP server). + +## Stack + +- TypeScript, ESNext modules, compiled to `build/` +- MCP SDK: `@modelcontextprotocol/sdk` +- Testing: Jest + `jest-fetch-mock` (run with `npm test`) +- Build: `npm run build` (tsc + chmod 755 on entry point) +- Inspector: `npm run inspector` — launches MCP inspector UI against `build/index.js` + +## Source layout + +4 source files in `src/`: +- `index.ts` — server init, MCP handler registration, env var validation +- `make.ts` — Make API client (`Make` class + `Scenarios` class) +- `utils.ts` — `remap()` schema converter, `MakeError`, `createMakeError` +- `types.ts` — TypeScript interfaces for API shapes + +Tests in `test/server.spec.ts`. Fixtures in `test/mocks/` (4 JSON files). + +## Required environment variables + +All three must be set or process exits with code 1 on startup: +- `MAKE_API_KEY` — used as `Token ` (not Bearer) +- `MAKE_ZONE` — API base hostname (e.g. `eu2.make.com`) +- `MAKE_TEAM` — integer team ID (parsed via `parseInt`, no validation) + +## Key architectural patterns + +### Dynamic tool list +There is no static tool registry. On every `tools/list` MCP request, the server queries Make API for scenarios, filters to `scheduling.type === 'on-demand'`, fetches each scenario's input interface in parallel, and converts them to MCP tools. Tool names are `run_scenario_{id}`. + +### Make API client (`src/make.ts`) +- URL assembly: paths starting with `/` get `https://${MAKE_ZONE}/api/v2` prepended; `//`-prefixed paths get `https:` prepended; absolute URLs pass through unchanged +- Every request gets `user-agent: MakeMCPServer/0.1.0` and `authorization: Token ` headers +- Run calls use `{ data: , responsive: true }` — `responsive: true` causes synchronous/awaited execution +- `listOrganization()` is defined but never called from `index.ts` + +### Schema conversion — `remap()` (`src/utils.ts`) +Recursively converts Make `Input[]` → JSON Schema. Always called with a synthetic wrapper `{ type: 'collection', spec: Input[] }`, so top-level `inputSchema` is always `type: object`. Make types map to: `text/date/json` → `string`, `number` → `number`, `boolean` → `boolean`, `collection` → `object`, `array` → `array`, `select` → `string` with `enum`. Field `help` maps to `description` (via `noEmpty()` — returns `undefined` for falsy). `default` included only when not `''` and not `null`. + +### Error handling asymmetry +- `CallToolRequest` handler wraps `run()` in try/catch — MakeErrors surface as MCP `isError: true` responses +- `ListToolsRequest` handler has **no try/catch** — API errors propagate unhandled to the MCP SDK +- HTTP status >= 400 → `createMakeError()` tries JSON parse for `detail`/`message`/`suberrors`; falls back to `res.statusText` + +## Testing + +- `jest.config.ts`: `moduleNameMapper` strips `.js` extensions (ESM compat), `ts-jest` transform +- All HTTP mocked via `jest-fetch-mock` — `enableFetchMocks()` at module level, `fetchMock.resetMocks()` in `beforeEach` +- Mock pattern: `fetchMock.mockResponse(req => { if (req.url !== expectedUrl) throw ...; return Promise.resolve({ body, headers }) })` +- Error test pattern: try/catch with `instanceof MakeError` guard, then field-by-field assertions + +## Distribution + +- Published as `@makehq/mcp-server`, bin entry `mcp-server-make` +- MCP registry configs: `smithery.yaml`, `glama.json` +- `Dockerfile` present for containerized deployment + +## When in Plan Mode +- Make the plan extremely concise. Sacrifice grammar for the sake of concision. +- Interview user in detail (for Claude: use the AskUserQuestionTool) about literally anything: technical implementation, UI & UX, concerns, tradeoffs, etc. but make sure the questions are not obvious. Be very in-depth and continue interviewing the user continually until it's complete. Use the answers to create a detailed spec. +- Make assumptions explicit: When you must proceed under uncertainty, list assumptions up front and continue. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..43c994c --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md From 94507208e689b7fd11428721fc907193eb05fd4c Mon Sep 17 00:00:00 2001 From: Frantisek Pac Date: Mon, 23 Mar 2026 14:57:14 +0100 Subject: [PATCH 2/2] chore: improve context file with conditions --- AGENTS.md | 97 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 54 insertions(+), 43 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 1bad53d..e9aaca6 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,65 +1,76 @@ # make-mcp-server -TypeScript MCP (Model Context Protocol) server that exposes Make.com on-demand scenarios as callable tools for AI assistants. Uses stdio transport (no HTTP server). +TypeScript MCP server exposing Make.com on-demand scenarios as callable tools for AI assistants. Stdio transport, no HTTP. -## Stack +## Project map + +- `src/index.ts` — server init, MCP handler registration, env var validation +- `src/make.ts` — Make API client (`Make` + `Scenarios` classes) +- `src/utils.ts` — `remap()` schema converter, `MakeError`, `createMakeError` +- `src/types.ts` — TypeScript interfaces +- `test/server.spec.ts` — tests; fixtures in `test/mocks/` -- TypeScript, ESNext modules, compiled to `build/` -- MCP SDK: `@modelcontextprotocol/sdk` -- Testing: Jest + `jest-fetch-mock` (run with `npm test`) -- Build: `npm run build` (tsc + chmod 755 on entry point) -- Inspector: `npm run inspector` — launches MCP inspector UI against `build/index.js` +## Stack -## Source layout +TypeScript, ESNext modules → `build/`. MCP SDK (`@modelcontextprotocol/sdk`). Jest + `jest-fetch-mock`. -4 source files in `src/`: -- `index.ts` — server init, MCP handler registration, env var validation -- `make.ts` — Make API client (`Make` class + `Scenarios` class) -- `utils.ts` — `remap()` schema converter, `MakeError`, `createMakeError` -- `types.ts` — TypeScript interfaces for API shapes + -Tests in `test/server.spec.ts`. Fixtures in `test/mocks/` (4 JSON files). +| Command | What it does | +|---|---| +| `npm run build` | tsc + chmod 755 on entry point | +| `npm test` | Run Jest tests | +| `npm run inspector` | Launch MCP inspector UI against `build/index.js` | + -## Required environment variables + -All three must be set or process exits with code 1 on startup: +Three required env vars (process exits 1 if missing): - `MAKE_API_KEY` — used as `Token ` (not Bearer) - `MAKE_ZONE` — API base hostname (e.g. `eu2.make.com`) -- `MAKE_TEAM` — integer team ID (parsed via `parseInt`, no validation) +- `MAKE_TEAM` — integer team ID + + + + +No static tool registry. On every `tools/list` request the server queries Make API for scenarios, filters to `scheduling.type === 'on-demand'`, fetches input interfaces in parallel, converts via `remap()` to JSON Schema. Tool names: `run_scenario_{id}`. -## Key architectural patterns +Run calls use `{ data: , responsive: true }` for synchronous execution. + -### Dynamic tool list -There is no static tool registry. On every `tools/list` MCP request, the server queries Make API for scenarios, filters to `scheduling.type === 'on-demand'`, fetches each scenario's input interface in parallel, and converts them to MCP tools. Tool names are `run_scenario_{id}`. + -### Make API client (`src/make.ts`) -- URL assembly: paths starting with `/` get `https://${MAKE_ZONE}/api/v2` prepended; `//`-prefixed paths get `https:` prepended; absolute URLs pass through unchanged -- Every request gets `user-agent: MakeMCPServer/0.1.0` and `authorization: Token ` headers -- Run calls use `{ data: , responsive: true }` — `responsive: true` causes synchronous/awaited execution -- `listOrganization()` is defined but never called from `index.ts` +URL assembly: `/`-prefixed → `https://${MAKE_ZONE}/api/v2` prepended; `//`-prefixed → `https:` prepended; absolute URLs pass through. -### Schema conversion — `remap()` (`src/utils.ts`) -Recursively converts Make `Input[]` → JSON Schema. Always called with a synthetic wrapper `{ type: 'collection', spec: Input[] }`, so top-level `inputSchema` is always `type: object`. Make types map to: `text/date/json` → `string`, `number` → `number`, `boolean` → `boolean`, `collection` → `object`, `array` → `array`, `select` → `string` with `enum`. Field `help` maps to `description` (via `noEmpty()` — returns `undefined` for falsy). `default` included only when not `''` and not `null`. +Every request gets `user-agent: MakeMCPServer/0.1.0` and `authorization: Token ` headers. + -### Error handling asymmetry -- `CallToolRequest` handler wraps `run()` in try/catch — MakeErrors surface as MCP `isError: true` responses -- `ListToolsRequest` handler has **no try/catch** — API errors propagate unhandled to the MCP SDK -- HTTP status >= 400 → `createMakeError()` tries JSON parse for `detail`/`message`/`suberrors`; falls back to `res.statusText` + -## Testing +`remap()` recursively converts Make `Input[]` → JSON Schema. Always called with synthetic wrapper `{ type: 'collection', spec: Input[] }`, so top-level is always `type: object`. See `src/utils.ts` for the type mapping. + + + + +Error handling asymmetry: +- `CallToolRequest` handler wraps `run()` in try/catch — MakeErrors → MCP `isError: true` +- `ListToolsRequest` handler has **no try/catch** — errors propagate unhandled +- HTTP status >= 400 → `createMakeError()` tries JSON parse for `detail`/`message`/`suberrors`; falls back to `statusText` + + + -- `jest.config.ts`: `moduleNameMapper` strips `.js` extensions (ESM compat), `ts-jest` transform - All HTTP mocked via `jest-fetch-mock` — `enableFetchMocks()` at module level, `fetchMock.resetMocks()` in `beforeEach` -- Mock pattern: `fetchMock.mockResponse(req => { if (req.url !== expectedUrl) throw ...; return Promise.resolve({ body, headers }) })` -- Error test pattern: try/catch with `instanceof MakeError` guard, then field-by-field assertions +- Mock pattern: `fetchMock.mockResponse(req => { if (req.url !== expected) throw ...; return Promise.resolve({ body, headers }) })` +- Error tests: try/catch with `instanceof MakeError` guard, field-by-field assertions +- `jest.config.ts`: `moduleNameMapper` strips `.js` extensions (ESM compat) + + + -## Distribution +Published as `@makehq/mcp-server`, bin entry `mcp-server-make`. Registry configs: `smithery.yaml`, `glama.json`. `Dockerfile` for containerized deployment. + -- Published as `@makehq/mcp-server`, bin entry `mcp-server-make` -- MCP registry configs: `smithery.yaml`, `glama.json` -- `Dockerfile` present for containerized deployment +## Keeping AGENTS.md current -## When in Plan Mode -- Make the plan extremely concise. Sacrifice grammar for the sake of concision. -- Interview user in detail (for Claude: use the AskUserQuestionTool) about literally anything: technical implementation, UI & UX, concerns, tradeoffs, etc. but make sure the questions are not obvious. Be very in-depth and continue interviewing the user continually until it's complete. Use the answers to create a detailed spec. -- Make assumptions explicit: When you must proceed under uncertainty, list assumptions up front and continue. +When your changes alter anything described in this file — project map, env vars, architectural patterns, API client behavior, error handling, test patterns, or packaging — notify the user that AGENTS.md should be updated and suggest the specific edit.