Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/cherry-pick-prompt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/create-release-branch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ jobs:
echo "Creating release branch for version $MAJOR.$MINOR.x"

- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 0
ref: ${{ inputs.base_branch }}

- name: Setup Node
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version-file: ".nvmrc"
cache: "yarn"
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/publish-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ jobs:

steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v6
with:
fetch-depth: 0

Expand Down Expand Up @@ -66,7 +66,7 @@ jobs:
echo "Release line: $RELEASE_LINE"

- name: Setup Node
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version-file: ".nvmrc"
cache: "yarn"
Expand Down Expand Up @@ -161,7 +161,7 @@ jobs:
- name: Generate AI changelog
id: ai_changelog
if: ${{ inputs.dry_run != true && inputs.release_type == 'stable' }}
uses: actions/github-script@v7
uses: actions/github-script@v8
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
VERSION: v${{ steps.version.outputs.version }}
Expand Down
29 changes: 25 additions & 4 deletions .github/workflows/push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ jobs:
matrix:
node-version: [20.x, 22.x, 24.x]
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6

- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
cache: 'yarn'
Expand All @@ -42,5 +42,26 @@ jobs:
- name: Build
run: yarn build

- name: Test
run: yarn test
- name: Test with coverage
run: yarn test:coverage --coverageReporters=text --coverageReporters=json-summary

- name: Coverage summary
if: always()
run: |
if [ -f coverage/coverage-summary.json ]; then
echo "## Test Coverage (Node ${{ matrix.node-version }})" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Category | Statements | Branches | Functions | Lines |" >> $GITHUB_STEP_SUMMARY
echo "|----------|-----------|----------|-----------|-------|" >> $GITHUB_STEP_SUMMARY
node -e "
const s = require('./coverage/coverage-summary.json').total;
const row = ['All files', s.statements.pct + '%', s.branches.pct + '%', s.functions.pct + '%', s.lines.pct + '%'];
console.log('| ' + row.join(' | ') + ' |');
" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
else
echo "## Test Coverage (Node ${{ matrix.node-version }})" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "> Coverage data not available — the test step may have failed before generating coverage." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
fi
81 changes: 0 additions & 81 deletions CHANGELOG.md

This file was deleted.

130 changes: 130 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
# CLAUDE.md - Project Guide for mcp-from-openapi

## Project Overview

**mcp-from-openapi** converts OpenAPI 3.0/3.1 specifications into MCP (Model Context Protocol) tool definitions. It handles parameter resolution, schema conversion, security configuration, SSRF-safe `$ref` dereferencing, and format-to-schema enrichment.

## Architecture

```text
OpenAPI Spec (JSON/YAML/URL/File)
|
v
OpenAPIToolGenerator (src/generator.ts)
|-- initialize(): dereference $refs, then validate
|-- generateTools(): iterate paths/operations
|-- generateTool(): build a single McpOpenAPITool
|
|-- ParameterResolver (src/parameter-resolver.ts)
| resolves params + requestBody into inputSchema + mapper
|
|-- ResponseBuilder (src/response-builder.ts)
| builds outputSchema from responses
|
|-- Format Resolution (src/format-resolver.ts)
| enriches schemas with format constraints (optional)
|
v
McpOpenAPITool { name, description, inputSchema, outputSchema, mapper, metadata }
```

## Key Files

| File | Purpose |
|------|---------|
| `src/generator.ts` | Main entry point. Factory methods (`fromJSON`, `fromYAML`, `fromURL`, `fromFile`), tool generation, SSRF protection, `$ref` dereferencing |
| `src/types.ts` | All type definitions, `toJsonSchema()` conversion, `isReferenceObject()` guard |
| `src/parameter-resolver.ts` | Resolves OpenAPI parameters + requestBody into flat inputSchema with conflict resolution |
| `src/response-builder.ts` | Builds outputSchema from OpenAPI responses with content-type and status code preferences |
| `src/format-resolver.ts` | Format-to-schema resolution. Built-in resolvers for uuid, date-time, email, int32, etc. |
| `src/schema-builder.ts` | Static utilities: merge, union, clone, flatten, simplify, withFormat, etc. |
| `src/security-resolver.ts` | Resolves security schemes (Bearer, Basic, Digest, API Key, OAuth2, OpenID Connect) |
| `src/validator.ts` | Validates OpenAPI document structure |
| `src/errors.ts` | Error class hierarchy: LoadError, ParseError, ValidationError, GenerationError, SchemaError |
| `src/index.ts` | Barrel file for public exports |

## Development Commands

```bash
yarn test # Run all tests (unit + integration)
yarn test:unit # Run unit tests only
yarn test:integration # Run integration tests only
yarn test:coverage # Run tests with coverage report
yarn build # Build CJS + ESM + type declarations
yarn build:cjs # Build CommonJS output only
yarn build:esm # Build ESM output only
yarn build:types # Emit TypeScript declarations only
yarn clean # Remove dist/ and coverage/
```

## Build System

- **Bundler**: esbuild (separate CJS and ESM builds)
- **Type declarations**: tsc with `tsconfig.lib.json`
- **Packages**: external (not bundled into output) via `--packages=external`
- **CJS output**: `dist/index.js`
- **ESM output**: `dist/esm/index.mjs`
- **Types**: `dist/index.d.ts`

## Testing

- **Framework**: Jest 29 with SWC transformer (`@swc/jest`)
- **Coverage provider**: V8 (`coverageProvider: 'v8'` in jest.config.js)
- **Coverage target**: 100% statements, branches, functions, lines
- **Unit tests**: `src/__tests__/*.spec.ts` (one per module)
- **Integration tests**: `src/__tests__/integration.spec.ts` (full pipeline, imports from entrypoint only)
- **Coverage exclusion**: `src/index.ts` (barrel file)

### Testing Patterns

- **Inline specs**: Tests create OpenAPI spec objects directly (no fixture files)
- **Mock fetch**: URL loading tests mock `global.fetch` with `jest.fn()`
- **Temp files**: File loading tests create temp files in `os.tmpdir()`, clean up in `finally`
- **Spy on dereference**: SSRF tests spy on `$RefParser.dereference` to inspect options without making network calls
- **`c8 ignore next`**: Used for defensive branches unreachable through normal code paths (V8 coverage ignores)
- **`transformIgnorePatterns`**: `@apidevtools/json-schema-ref-parser` is ESM-only and must be transformed by SWC

### ESM Dependency Handling

`@apidevtools/json-schema-ref-parser` v15 is ESM-only. The project uses dynamic `import()` in `generator.ts` so it works from both CJS and ESM contexts. Jest transforms the package via `transformIgnorePatterns` in `jest.config.js`.

## Options Flow

```text
LoadOptions (factory methods)
-> constructor (normalizes defaults)
-> initialize()
-> $RefParser.dereference() [if dereference: true]
-> Validator.validate() [if validate: true]

GenerateOptions (generateTools/generateTool)
-> ParameterResolver(namingStrategy)
.resolve(operation, pathParams, security, includeSecurityInInput)
-> ResponseBuilder(preferredStatusCodes, includeAllResponses)
.build(responses)
-> resolveSchemaFormats(schema, resolvers) [if resolveFormats/formatResolvers set]
```

## Key Conventions

- `toJsonSchema()` converts OpenAPI SchemaObject to JSON Schema (handles exclusiveMin/Max boolean-to-numeric conversion)
- Schemas pass through `toJsonSchema()` in both ParameterResolver and ResponseBuilder
- Metadata is attached via `x-` prefixed properties (`x-parameter-location`, `x-status-code`, `x-content-type`)
- The `mapper` array maps inputSchema keys to their HTTP locations (path/query/header/body/cookie)
- Security info lives on mapper entries (not on inputSchema unless `includeSecurityInInput: true`)
- Format resolution is a post-processing step applied to final inputSchema/outputSchema

## Documentation

- All docs live in `docs/` folder
- `docs/FORMAT_RESOLUTION.md` — Format resolution feature docs (built-in resolvers, custom resolvers, standalone usage)

### README Links for npm

All links in `README.md` must use **absolute GitHub URLs** (not relative paths) because npm renders README on its own domain and relative links break. Use the format:

```
https://github.com/agentfront/mcp-from-openapi/blob/main/docs/<file>.md
```

When adding new docs or links to README, always use absolute URLs pointing to the `main` branch.
29 changes: 15 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,19 +138,20 @@ function buildRequest(tool: McpOpenAPITool, input: Record<string, any>) {

| Document | Description |
|----------|-------------|
| [Getting Started](docs/getting-started.md) | Loading specs, generating tools, building requests |
| [Configuration](docs/configuration.md) | LoadOptions, GenerateOptions, RefResolutionOptions |
| [Parameter Conflicts](docs/parameter-conflicts.md) | How conflict detection and resolution works |
| [Response Schemas](docs/response-schemas.md) | Output schemas, status codes, oneOf unions |
| [Security](docs/security.md) | SecurityResolver, all auth types, custom resolvers |
| [SSRF Prevention](docs/ssrf-prevention.md) | Ref resolution security, blocked IPs and hosts |
| [Naming Strategies](docs/naming-strategies.md) | Custom tool naming and conflict resolvers |
| [SchemaBuilder](docs/schema-builder.md) | JSON Schema utility methods |
| [Error Handling](docs/error-handling.md) | Error classes, context, and patterns |
| [x-frontmcp Extension](docs/x-frontmcp.md) | Custom OpenAPI extension for MCP annotations |
| [API Reference](docs/api-reference.md) | Complete types, interfaces, and exports |
| [Examples](docs/examples.md) | MCP server, Zod, filtering, security, and more |
| [Architecture](docs/architecture.md) | System overview, data flow, design patterns |
| [Getting Started](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/getting-started.md) | Loading specs, generating tools, building requests |
| [Configuration](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/configuration.md) | LoadOptions, GenerateOptions, RefResolutionOptions |
| [Parameter Conflicts](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/parameter-conflicts.md) | How conflict detection and resolution works |
| [Response Schemas](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/response-schemas.md) | Output schemas, status codes, oneOf unions |
| [Security](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/security.md) | SecurityResolver, all auth types, custom resolvers |
| [SSRF Prevention](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/ssrf-prevention.md) | Ref resolution security, blocked IPs and hosts |
| [Format Resolution](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/FORMAT_RESOLUTION.md) | Format-to-schema enrichment (uuid, date-time, email, int32, etc.) |
| [Naming Strategies](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/naming-strategies.md) | Custom tool naming and conflict resolvers |
| [SchemaBuilder](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/schema-builder.md) | JSON Schema utility methods |
| [Error Handling](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/error-handling.md) | Error classes, context, and patterns |
| [x-frontmcp Extension](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/x-frontmcp.md) | Custom OpenAPI extension for MCP annotations |
| [API Reference](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/api-reference.md) | Complete types, interfaces, and exports |
| [Examples](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/examples.md) | MCP server, Zod, filtering, security, and more |
| [Architecture](https://github.com/agentfront/mcp-from-openapi/blob/main/docs/architecture.md) | System overview, data flow, design patterns |

## Requirements

Expand All @@ -169,4 +170,4 @@ Contributions are welcome! Please see our [issues page](https://github.com/agent

## License

[Apache 2.0](LICENSE)
[Apache 2.0](https://github.com/agentfront/mcp-from-openapi/blob/main/LICENSE)
Loading