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
612 changes: 59 additions & 553 deletions README.md

Large diffs are not rendered by default.

567 changes: 567 additions & 0 deletions docs/api-reference.md

Large diffs are not rendered by default.

167 changes: 167 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
# Architecture

[Home](../README.md) | [API Reference](./api-reference.md)

---

## System Overview

```
OpenAPIToolGenerator (Main Entry Point)
├── Validator → OpenAPI document validation
├── ParameterResolver → Parameter conflict resolution & mapping
├── ResponseBuilder → Output schema generation
├── SchemaBuilder → Schema manipulation utilities
└── SecurityResolver → Framework-agnostic auth resolution
```

---

## Data Flow

```
User Input (URL / File / String / Object)
Load & Parse
OpenAPI Document
Validate (optional)
Dereference $refs (optional, with SSRF protection)
Filter Operations
For Each Operation:
├── ParameterResolver → inputSchema + mapper
├── ResponseBuilder → outputSchema
└── Metadata Extractor → metadata (security, servers, tags, etc.)
McpOpenAPITool[]
```

---

## Core Components

### OpenAPIToolGenerator

**Responsibility:** Entry point, orchestration, document management.

- Provides four factory methods for loading specs from different sources
- Manages the dereference lifecycle (lazy initialization)
- Coordinates validation, parameter resolution, response building, and metadata extraction
- Handles SSRF protection for `$ref` resolution
- Generates tool names (from operationId or path+method)

**Key files:** `src/generator.ts`

### ParameterResolver

**Responsibility:** Extract parameters, detect conflicts, generate input schema and mapper.

**Algorithm:**
1. Collect parameters from path item + operation (path, query, header, cookie)
2. Extract request body properties as body parameters
3. Group all parameters by name
4. Detect conflicts (same name in multiple locations)
5. Apply naming strategy to resolve conflicts
6. Build combined `inputSchema` with unique property names
7. Create `ParameterMapper[]` entries mapping inputs to request locations
8. Process security requirements (add to mapper, optionally to schema)

**Key files:** `src/parameter-resolver.ts`

### ResponseBuilder

**Responsibility:** Extract response schemas, handle multiple status codes.

- Selects content type by preference (JSON > HAL+JSON > problem+JSON > XML > text)
- Handles no-content responses (204) as `type: 'null'`
- Builds `oneOf` unions for multiple responses or selects preferred
- Annotates schemas with `x-status-code` and `x-content-type`
- Falls back through 2xx, 3xx, then first available when preferred codes aren't found

**Key files:** `src/response-builder.ts`

### Validator

**Responsibility:** Validate OpenAPI 3.0.x and 3.1.x document structure.

**Checks (errors):**
- OpenAPI version field present and valid
- `info`, `info.title`, `info.version` present
- Paths start with `/`
- Path parameters are defined and required
- Operations have responses
- Parameters have name, `in`, and schema/content

**Checks (warnings):**
- No paths defined
- No servers defined
- No operation IDs
- Security requirements without schemes

**Key files:** `src/validator.ts`

### SchemaBuilder

**Responsibility:** Static utilities for JSON Schema manipulation.

Provides factory methods (object, array, string, number, etc.), composition (merge, union), modification (withDescription, withRange, etc.), and utilities (clone, flatten, simplify, removeRefs).

**Key files:** `src/schema-builder.ts`

### SecurityResolver

**Responsibility:** Map OpenAPI security schemes to actual auth values.

- Resolves HTTP (bearer, basic, digest), API Key, OAuth2, OpenID Connect
- Detects signature-based auth (HMAC, AWS, custom)
- Supports custom resolvers for framework-specific auth
- Provides `checkMissingSecurity()` for validation
- Provides `signRequest()` for signature-based auth

**Key files:** `src/security-resolver.ts`

---

## Design Patterns

| Pattern | Usage |
|---------|-------|
| **Factory** | `OpenAPIToolGenerator.fromURL()`, `.fromFile()`, `.fromYAML()`, `.fromJSON()` |
| **Strategy** | `NamingStrategy` for parameter conflict resolution and tool naming |
| **Builder** | `SchemaBuilder` for constructing schemas fluently |
| **Template Method** | Tool generation pipeline (validate → dereference → resolve → build → extract) |

---

## Extension Points

1. **Custom Naming Strategies** -- Implement `NamingStrategy` to control parameter renaming and tool naming
2. **Custom Filters** -- Use `filterFn` in `GenerateOptions` to select which operations become tools
3. **Custom Security Resolution** -- Use `customResolver` in `SecurityContext` for framework-specific auth
4. **Custom Signature Generation** -- Use `signatureGenerator` in `SecurityContext` for signature-based auth
5. **Schema Transformation** -- Use `SchemaBuilder` utilities post-generation

---

## Module Structure

```
src/
├── index.ts # Public exports
├── generator.ts # OpenAPIToolGenerator class
├── parameter-resolver.ts # ParameterResolver class
├── response-builder.ts # ResponseBuilder class
├── security-resolver.ts # SecurityResolver class + types
├── schema-builder.ts # SchemaBuilder class
├── validator.ts # Validator class
├── types.ts # Type definitions + utility functions
└── errors.ts # Error class hierarchy
```

---

**Related:** [API Reference](./api-reference.md) | [Getting Started](./getting-started.md)
151 changes: 151 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
# Configuration

[Home](../README.md) | [Getting Started](./getting-started.md) | [API Reference](./api-reference.md)

---

## LoadOptions

Passed to factory methods (`fromURL`, `fromFile`, `fromYAML`, `fromJSON`).

```typescript
const generator = await OpenAPIToolGenerator.fromURL(url, {
dereference: true,
baseUrl: 'https://staging.api.example.com',
headers: { Authorization: 'Bearer token' },
timeout: 15000,
validate: true,
followRedirects: true,
refResolution: {
allowedProtocols: ['https'],
blockedHosts: ['evil.com'],
},
});
```

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `dereference` | `boolean` | `true` | Resolve all `$ref` pointers in the spec |
| `baseUrl` | `string` | `''` | Override server URLs from the spec |
| `headers` | `Record<string, string>` | `{}` | Custom HTTP headers for URL loading |
| `timeout` | `number` | `30000` | HTTP request timeout in milliseconds |
| `validate` | `boolean` | `true` | Validate the OpenAPI document on load |
| `followRedirects` | `boolean` | `true` | Follow HTTP redirects when loading from URL |
| `refResolution` | `RefResolutionOptions` | `{}` | Security settings for `$ref` resolution |

### RefResolutionOptions

Controls how external `$ref` pointers are resolved during dereferencing. See [SSRF Prevention](./ssrf-prevention.md) for details.

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `allowedProtocols` | `string[]` | `['http', 'https']` | Protocols allowed for external refs |
| `allowedHosts` | `string[]` | `[]` (all allowed) | Whitelist specific hostnames |
| `blockedHosts` | `string[]` | `[]` | Additional hostnames to block |
| `allowInternalIPs` | `boolean` | `false` | Disable built-in SSRF protection |

---

## GenerateOptions

Passed to `generateTools()` and `generateTool()`.

```typescript
const tools = await generator.generateTools({
includeOperations: ['getUser', 'createUser'],
excludeOperations: ['deleteUser'],
includeDeprecated: false,
includeAllResponses: true,
preferredStatusCodes: [200, 201],
maxSchemaDepth: 10,
includeExamples: false,
includeSecurityInInput: false,
});
```

| Option | Type | Default | Description |
|--------|------|---------|-------------|
| `includeOperations` | `string[]` | - | Only include these operation IDs |
| `excludeOperations` | `string[]` | - | Exclude these operation IDs |
| `filterFn` | `(op: OperationWithContext) => boolean` | - | Custom filter function |
| `namingStrategy` | `NamingStrategy` | - | Custom naming for conflicts and tool names |
| `preferredStatusCodes` | `number[]` | `[200, 201, 204, 202, 203, 206]` | Preferred response codes (in order) |
| `includeDeprecated` | `boolean` | `false` | Include deprecated operations |
| `includeAllResponses` | `boolean` | `true` | Include all status codes as oneOf union |
| `maxSchemaDepth` | `number` | `10` | Maximum nesting depth for schemas |
| `includeExamples` | `boolean` | `false` | Include example values in schemas |
| `includeSecurityInInput` | `boolean` | `false` | Add security params to inputSchema |

### Filtering Operations

Three ways to filter which operations become tools:

**By operation ID:**

```typescript
// Include only specific operations
const tools = await generator.generateTools({
includeOperations: ['getUser', 'createUser'],
});

// Exclude specific operations
const tools = await generator.generateTools({
excludeOperations: ['deleteUser', 'adminReset'],
});
```

**By custom filter:**

The `filterFn` receives an `OperationWithContext` -- the OpenAPI operation object extended with `path` and `method` properties:

```typescript
// Only GET operations
const tools = await generator.generateTools({
filterFn: (op) => op.method === 'get',
});

// Only operations tagged "public"
const tools = await generator.generateTools({
filterFn: (op) => op.tags?.includes('public') ?? false,
});

// Combine: GET operations on /users paths
const tools = await generator.generateTools({
filterFn: (op) => op.method === 'get' && op.path.startsWith('/users'),
});
```

### includeSecurityInInput

By default (`false`), security parameters appear **only** in the mapper with a `security` field. Frameworks resolve auth from environment variables, context, or vaults -- not from user input.

When set to `true`, security parameters are also added to the `inputSchema` as required string properties, allowing callers to pass auth values directly as tool inputs.

### includeAllResponses

When `true` (default), the output schema is a `oneOf` union of all response status codes. Each variant includes an `x-status-code` annotation.

When `false`, only the single preferred status code schema is used (based on `preferredStatusCodes` order).

---

## NamingStrategy

Customize how parameter conflicts are resolved and how tools are named. See [Naming Strategies](./naming-strategies.md) for details.

```typescript
const tools = await generator.generateTools({
namingStrategy: {
conflictResolver: (paramName, location, index) => {
return `${location.toUpperCase()}_${paramName}`;
},
toolNameGenerator: (path, method, operationId) => {
return operationId ?? `${method}_${path.replace(/\//g, '_')}`;
},
},
});
```

---

**Related:** [Getting Started](./getting-started.md) | [SSRF Prevention](./ssrf-prevention.md) | [Naming Strategies](./naming-strategies.md)
Loading
Loading