Skip to content
Merged
Show file tree
Hide file tree
Changes from 13 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
6 changes: 3 additions & 3 deletions .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0

- name: Install uv
uses: astral-sh/setup-uv@v4
uses: astral-sh/setup-uv@e92bafb6253dcd438e0484186d7669ea7a8ca1cc # v6.4.3
with:
python-version: "3.11"
enable-cache: true
Expand All @@ -30,7 +30,7 @@ jobs:
- name: Deploy to GitHub Pages
if: github.ref == 'refs/heads/main'
uses: peaceiris/actions-gh-pages@v3
uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./site
6 changes: 3 additions & 3 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0

- name: Install uv
uses: astral-sh/setup-uv@v5
uses: astral-sh/setup-uv@e92bafb6253dcd438e0484186d7669ea7a8ca1cc # v6.4.3
with:
python-version: "3.11"
enable-cache: true
Expand All @@ -21,7 +21,7 @@ jobs:
run: uv sync --all-extras

- name: Run Ruff
uses: astral-sh/ruff-action@v3
uses: astral-sh/ruff-action@0c50076f12c38c3d0115b7b519b54a91cb9cf0ad # v3.5.0
with:
args: check .

Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,19 +13,19 @@ jobs:
release-please:
runs-on: ubuntu-latest
steps:
- uses: google-github-actions/release-please-action@v4
- uses: google-github-actions/release-please-action@e4dc86ba9405554aeba3c6bb2d169500e7d3b4ee # v4.1.1
id: release
with:
config-file: .release-please-config.json
manifest-file: .release-please-manifest.json

# Only release to PyPI when a new release is created
- uses: actions/checkout@v4
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
if: ${{ steps.release.outputs.release_created }}

- name: Install uv
if: ${{ steps.release.outputs.release_created }}
uses: astral-sh/setup-uv@v5
uses: astral-sh/setup-uv@e92bafb6253dcd438e0484186d7669ea7a8ca1cc # v6.4.3
with:
python-version: "3.11"
enable-cache: true
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ jobs:
STACKONE_API_KEY: ${{ secrets.STACKONE_API_KEY }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0

- name: Install uv
uses: astral-sh/setup-uv@v5
uses: astral-sh/setup-uv@e92bafb6253dcd438e0484186d7669ea7a8ca1cc # v6.4.3
with:
python-version: "3.11"
enable-cache: true
Expand Down
12 changes: 12 additions & 0 deletions .mcp.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"mcpServers": {
"context7": {
"type": "http",
"url": "https://mcp.context7.com/mcp"
},
"grep": {
"type": "http",
"url": "https://mcp.grep.app"
}
}
}
120 changes: 120 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

## Cursor Rules

- @./.cursor/rules/package-installation
- @./.cursor/rules/no-relative-imports
- @./.cursor/rules/uv-scripts
- @./.cursor/rules/release-please-standards
- @./.cursor/rules/examples-standards

## Project Overview

StackOne AI SDK is a Python library that provides a unified interface for accessing various SaaS tools through AI-friendly APIs. It acts as a bridge between AI applications and multiple SaaS platforms (HRIS, CRM, ATS, LMS, Marketing, etc.) with support for OpenAI, LangChain, CrewAI, and Model Context Protocol (MCP).

## Essential Development Commands

```bash
# Setup and installation
make install # Install dependencies and pre-commit hooks

# Code quality
make lint # Run ruff linting
make lint-fix # Auto-fix linting issues
make mypy # Run type checking

# Testing
make test # Run all tests
make test-tools # Run tool-specific tests
make test-examples # Run example tests

# Documentation
make docs-serve # Build and serve docs locally (http://localhost:8000)
make docs-build # Build docs for deployment

# MCP Development
make mcp-inspector # Run MCP server inspector for debugging
```

## Code Architecture

### Core Components

1. **StackOneToolSet** (`stackone_ai/toolset.py`): Main entry point
- Handles authentication (API key + optional account ID)
- Manages tool loading with glob pattern filtering
- Provides format converters for OpenAI/LangChain

2. **Models** (`stackone_ai/models.py`): Data structures
- `StackOneTool`: Base class with execution logic
- `Tools`: Container for managing multiple tools
- Format converters for different AI frameworks

3. **OpenAPI Parser** (`stackone_ai/specs/parser.py`): Spec conversion
- Converts OpenAPI specs to tool definitions
- Handles file upload detection (`format: binary` → `type: file`)
- Resolves schema references

4. **MCP Server** (`stackone_ai/server.py`): Protocol implementation
- Async tool execution
- CLI interface via `stackmcp` command

### OpenAPI Specifications

All tool definitions are generated from OpenAPI specs in `stackone_ai/oas/`:
- `core.json`, `ats.json`, `crm.json`, `documents.json`, `hris.json`, `iam.json`, `lms.json`, `marketing.json`

## Key Development Patterns

### Tool Filtering
```python
# Use glob patterns for tool selection
tools = StackOneToolSet(include_tools=["hris_*", "!hris_create_*"])
```

### Authentication
```python
# Uses environment variables or direct configuration
toolset = StackOneToolSet(
api_key="your-api-key", # or STACKONE_API_KEY env var
account_id="optional-id" # or STACKONE_ACCOUNT_ID env var
)
```

### Type Safety
- Full type annotations required (Python 3.11+)
- Strict mypy configuration
- Use generics for better IDE support

### Testing
- Snapshot testing for tool parsing (`tests/snapshots/`)
- Async tests use `pytest-asyncio`
- Example validation: See @./.cursor/rules/examples-standards

## Important Considerations

1. **Dependencies**: See @./.cursor/rules/package-installation for uv dependency management
2. **Pre-commit**: Hooks configured for ruff and mypy - run on all commits
3. **Python Version**: Requires Python >=3.11
4. **Error Handling**: Custom exceptions (`StackOneError`, `StackOneAPIError`)
5. **File Uploads**: Binary parameters auto-detected from OpenAPI specs
6. **Context Window**: Tool loading warns when loading all tools (large context)

## Common Tasks

### Adding New SaaS Integration
1. Add OpenAPI spec to `stackone_ai/oas/`
2. Parser automatically converts to tool definitions
3. Test with `make test-tools`

### Modifying Tool Behavior
- Core execution logic in `StackOneTool.execute()` method
- HTTP configuration via `ExecuteConfig` class
- Response handling in `_process_response()`

### Updating Documentation
- Examples requirements: See @./.cursor/rules/examples-standards
- Run `make docs-serve` to preview changes
- MkDocs config in `mkdocs.yml`
30 changes: 28 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,44 @@ from stackone_ai import StackOneToolSet
toolset = StackOneToolSet() # Uses STACKONE_API_KEY env var
# Or explicitly: toolset = StackOneToolSet(api_key="your-api-key")

# Get HRIS-related tools
# Get HRIS-related tools with glob patterns
tools = toolset.get_tools("hris_*", account_id="your-account-id")
# Exclude certain tools with negative patterns
tools = toolset.get_tools(["hris_*", "!hris_delete_*"])

# Use a specific tool
# Use a specific tool with the new call method
employee_tool = tools.get_tool("hris_get_employee")
# Call with keyword arguments
employee = employee_tool.call(id="employee-id")
# Or with traditional execute method
employee = employee_tool.execute({"id": "employee-id"})
```

## Meta Tools (Beta)

Meta tools enable dynamic tool discovery and execution without hardcoding tool names:

```python
# Get meta tools for dynamic discovery
tools = toolset.get_tools("hris_*")
meta_tools = tools.meta_tools()

# Search for relevant tools using natural language
filter_tool = meta_tools.get_tool("meta_filter_relevant_tools")
results = filter_tool.call(query="manage employees", limit=5)

# Execute discovered tools dynamically
execute_tool = meta_tools.get_tool("meta_execute_tool")
result = execute_tool.call(toolName="hris_list_employees", params={"limit": 10})
```

## Features

- Unified interface for multiple SaaS tools
- AI-friendly tool descriptions and parameters
- **Tool Calling**: Direct method calling with `tool.call()` for intuitive usage
- **Glob Pattern Filtering**: Advanced tool filtering with patterns like `"hris_*"` and exclusions `"!hris_delete_*"`
- **Meta Tools** (Beta): Dynamic tool discovery and execution based on natural language queries
- Integration with popular AI frameworks:
- OpenAI Functions
- LangChain Tools
Expand Down
Loading
Loading