Skip to content
Merged
Show file tree
Hide file tree
Changes from 9 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 .claude/CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
@../cursor_rules.md
Rules for Claude are in @AGENTS.md
126 changes: 126 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
# Project structure, technologies and architecture conventions

## Technologies used


- **uv** - Fast Python package installer and resolver
- **Python 3.11** - Modern Python with type hints and performance improvements
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- **Python 3.11** - Modern Python with type hints and performance improvements
- **Python 3.13** - Modern Python with type hints and performance improvements

- **FastMCP** - MCP server implementation
- **Pytest** - Testing framework with fixtures and plugins
- **Pydantic** - Data validation using Python type annotations
- **Structlog** - Structured logging for better observability

## Dependencies Management

1. **Use pyproject.toml with uv**
- Use `pyproject.toml` for dependency management, not requirements.txt
- Works well with `uv` for fast, reliable package management
- Properly specify dependencies with version constraints
- Use `uv sync` to install dependencies

2. **Example pyproject.toml**
```toml
[build-system]
requires = ["setuptools>=42", "wheel"]
build-backend = "setuptools.build_meta"

[project]
name = "my-mcp-server"
version = "0.1.0"
description = "My MCP server"
requires-python = ">=3.9"
dependencies = [
"mcp>=0.2.0",
"requests>=2.28.0",
]
```

## Server Implementation Guidelines

1. **Do NOT use uvicorn or fastapi with MCP/FastMCP**
- MCP has its own server implementation
- FastMCP/MCP can run directly using `mcp.run()` with no need for external web servers
- Avoid adding uvicorn or fastapi to dependencies
- Do not use `uvicorn.run(...)` in code

2. **Use the correct server method**
- Use `mcp.run()` to start the server (no additional parameters needed for stdio transport)
- Example: `mcp.run()` instead of `uvicorn.run(mcp.app, ...)`

3. **Dependencies**
- Only include required dependencies
- For basic MCP implementation, only `mcp` or `fastmcp` and possibly `requests` are needed
- Do not include web server packages unnecessarily



## Code Organization and Imports

1. **Use `src` as the root code directory**
- Ensure all code is placed within the `src` directory
- Handle imports accordingly by using the appropriate package path
- Example: `from src.gitguardian.your_module import YourClass`

2. **FastMCP imports must use the correct package path**
- All imports concerning FastMCP must be done under `mcp.server.fastmcp`
- Example: `from mcp.server.fastmcp import FastMCP` instead of direct imports

This guide ensures all MCP implementations follow the project's standards of using native capabilities rather than external web servers.


# Lower level Python rules

## General Guidelines

- Follow PEP 8 style guidelines
- Add docstrings to all public functions and classes
- Keep imports organized and sorted
- Don't use lazy/deferred imports, except inside Celery tasks definitions

## Running tests

To run the tests, `uv run pytest`

## Creating tests :

- We use pytest, and plain classes. Don't use unittest classes
- Use project fixtures (`test_account`, `owner_client`, `api_client`) instead of creating new instances
- file naming convention : `test_<whatever>.py`
- don't use self.assertEqual (and so on) helpers but only assert
- The docstring of every test function must follow this format :

```
"""
GIVEN ...
WHEN ...
THEN ...
"""
```

## Variable names

Use clear variable and function names that indicate their purpose without being overly verbose.
Follow established conventions where appropriate (e.g., `i` for loop indices, `df` for dataframes),
but ensure non-standard names are self-explanatory.
For example, prefer `calculate_user_discount(price, user_tier)` over `calc(p, t)`, but `i` is perfectly fine for a simple loop counter.


## **all** Lists

- Add an `__all__` list when using `import *` imports
- When provided, the `__all__ = []` list must be ordered alphabetically
- When adding new items to `__all__`, maintain alphabetical order
- Example:
```python
__all__ = [
"ClassA",
"ClassB",
"function_a",
"function_b",
]
```

## Typing

- Use typing for function signatures and return values
- Don't use `from typing import List` but rather `list`
72 changes: 0 additions & 72 deletions cursor_rules.md

This file was deleted.

45 changes: 43 additions & 2 deletions packages/gg_api_core/src/gg_api_core/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import httpx

from gg_api_core.host import is_self_hosted_instance
from gg_api_core.scopes import DEVELOPER_SCOPES
from urllib.parse import urlparse

# Setup logger
Expand Down Expand Up @@ -49,6 +48,48 @@ class IncidentValidity(str, Enum):
UNKNOWN = "unknown"


class TagNames(str, Enum):
REGRESSION = "REGRESSION" # Issue is a regression
HIST = (
"HIST"
) # Occurrence is visible and its Kind is history
PUBLICLY_EXPOSED = (
"PUBLICLY_EXPOSED"
) # Occurrence is visible and source is a public GitHub
TEST_FILE = (
"TEST_FILE"
) # Occurrence is visible and one of its insights is `test_file`
SENSITIVE_FILE = (
"SENSITIVE_FILE"
) # Occurrence is visible and one of its insights is `sensitive_filepath`
# DEPRECATED: Replaced by CHECK_RUN_SKIP_FALSE_POSITIVE but still there until we
# remove it from the public_api
DEPRECATED_IGNORED_IN_CHECK_RUN = (
"IGNORED_IN_CHECK_RUN"
) # Occurrence is visible and its GitHub check run a ignored
CHECK_RUN_SKIP_FALSE_POSITIVE = (
"CHECK_RUN_SKIP_FALSE_POSITIVE"
)
CHECK_RUN_SKIP_LOW_RISK = (
"CHECK_RUN_SKIP_LOW_RISK"
)
CHECK_RUN_SKIP_TEST_CRED = (
"CHECK_RUN_SKIP_TEST_CRED"
)
DEFAULT_BRANCH = (
"DEFAULT_BRANCH"
) # Occurrence is on the default branch of the repository
PUBLICLY_LEAKED = (
"PUBLICLY_LEAKED"
) # Issue's secret is publicly leaked outside the account perimeter
FALSE_POSITIVE = (
"FALSE_POSITIVE"
)
REVOCABLE_BY_GG = (
"REVOCABLE_BY_GG"
)


class GitGuardianClient:
"""Client for interacting with the GitGuardian API."""

Expand Down Expand Up @@ -195,7 +236,7 @@ async def _ensure_oauth_token(self):
return

logger.warning("Acquired OAuth lock, proceeding with authentication")
logger.info(f" Client API URL: {self.public_api_url}")
logger.info(f" Client API URL: {self.public_api_url}") # TODO(TIM)
logger.info(f" Client Dashboard URL: {self.dashboard_url}")
logger.info(f" Client Server Name: {getattr(self, 'server_name', 'None')}")

Expand Down
Loading
Loading