npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

openapi-graft

v0.1.5

Published

OpenAPI SDK generator with AST-level 3-way merge for preserved custom code, plus MCP server scaffolding

Readme

openapi-graft

OpenAPI SDK generator with AST-level 3-way merge for preserved custom code, plus MCP server scaffolding.

Features

  • Multi-language SDK generation: TypeScript, Python, Go, Java, Rust
  • AST-level 3-way merge: Preserves custom code across regenerations using @graft annotations
  • MCP server scaffolding: Generate Model Context Protocol servers from the same OpenAPI spec
  • CI-native: Runs as a CLI tool, no cloud dependency
  • Validation: Compiles merged output before writing to disk, fails CI if custom code breaks

Quick Start

# Install globally
npm install -g openapi-graft

# Or use with npx
npx openapi-graft init
npx openapi-graft generate

How It Works

Graft uses annotated regions for code preservation across regenerations:

| Layer | Function | |-------|----------| | Parser | Tree-sitter based - TypeScript, Python, Go, Java, Rust | | Base | Previous clean generation (stored in .graft/base/) | | Ours | Current working SDK with custom code | | Theirs | New generation from updated OpenAPI spec | | Merge Engine | Identifies @graft(preserve) annotated blocks, merges them into new generated classes | | Validator | Compiles the merged output before writing - fails CI if custom code broke the new interface |

Configuration

Create a graft.yml in your project root:

spec: ./openapi.json
sdks:
  - language: typescript
    output: ./sdks/ts
    package: "@yourcompany/sdk"
    preserve:
      - ./sdks/ts/src/custom/**/*.ts  # auto-annotated on first run
  - language: python
    output: ./sdks/python
    package: "yourcompany-sdk"
  - language: go
    output: ./sdks/go
    package: "github.com/yourcompany/sdk"
mcp:
  enabled: true
  output: ./mcp-server

Preserving Custom Code

Use @graft annotations to mark code that should survive regeneration:

TypeScript

// @graft(preserve) id="custom-validation"
async validateCustom(request: Request): Promise<Response> {
  // Your custom implementation
  // This survives SDK regeneration
}

Python

# @graft(preserve) id="custom-validation"
async def validate_custom(self, request):
    # Your custom implementation
    # This survives SDK regeneration
    pass

Go

// @graft(preserve) id="custom-handler"
func (api *API) CustomHandler(ctx context.Context, req Request) (*Response, error) {
    // Custom implementation survives regeneration
}

Java

// @graft(preserve) id="custom-handler"
public Object customHandler(String param) throws SDKException {
    // Custom implementation survives regeneration
}

Rust

/// @graft(preserve) id="custom-handler"
pub async fn custom_handler(&self, param: String) -> GraftResult<Value> {
    // Custom implementation survives regeneration
    Ok(Value::Null)
}

CLI Commands

# Initialize a new graft.yml
graft init

# Generate all SDKs
graft generate

# Generate MCP server
graft mcp

# Perform manual 3-way merge
graft merge --base ./base --ours ./ours --theirs ./theirs --language typescript --output ./merged

# Show status
graft status

Why Graft?

| Feature | OpenAPI Generator | Fern | Graft | |---------|------------------|------|-------| | Custom code survives regen | ❌ Overwritten | ⚠️ .fernignore (manual) | ✅ AST merge with annotations | | MCP server from same spec | ❌ No | ❌ No | ✅ Built-in | | Self-hosted / air-gapped | ✅ Yes | ⚠️ Docker only | ✅ CLI-native, no cloud | | Idiomatic output quality | ❌ Generic | ✅ High | ✅ Template-based |

License

MIT