MCPunk
by jurasofish
[project]
name = "mcpunk"
dynamic = ["version"]
description = "MCP tools for Roaming RAG"
authors = [{ name = "Michael Jurasoovic" }]
license = { text = "MIT" }
readme = "README.md"
requires-python = ">=3.11"
dependencies = [
"gitpython~=3.1.44",
"pydantic~=2.10.6",
"asttokens~=3.0.0",
"more-itertools~=10.6.0",
"mcp~=1.2.0",
"fastmcp~=0.4.1",
"beautifulsoup4~=4.13.3",
"uvicorn>=0.34.0,<1.0.0",
"watchdog~=6.0.0",
]
[project.scripts]
mcpunk = "mcpunk.run_mcp_server:main"
[build-system]
requires = ["hatchling>=1.21.0", "hatch-vcs>=0.4.0"]
build-backend = "hatchling.build"
[tool.hatch.version]
source = "vcs"
[tool.setuptools.dynamic]
version = {attr = "mcpunk.__version__"}
[tool.setuptools.packages.find]
include = ["mcpunk*"]
[project.optional-dependencies]
dev = [
"mypy~=1.15.0",
"pytest~=8.3.4",
"ruff~=0.9.9",
"pytest-cov~=6.0.0",
"deepdiff~=8.2.0",
"pre-commit~=4.1.0",
"line-profiler~=4.2.0",
]
[tool.mypy]
python_version = "3.11"
warn_return_any = true
warn_unused_configs = true
disallow_untyped_defs = true
ignore_missing_imports = true
show_error_codes = true
pretty = true
no_implicit_optional = true
implicit_reexport = false
strict_equality = true
strict=true
disallow_untyped_decorators = true
enable_error_code=[
"ignore-without-code",
"truthy-bool",
"unused-awaitable",
"possibly-undefined",
]
[tool.pydantic-mypy]
init_forbid_extra = true
init_typed = true
warn_required_dynamic_aliases = true
warn_untyped_fields = true
[tool.ruff]
target-version = "py311"
show-fixes = true
line-length = 100
lint.select = [
"ALL",
]
lint.ignore = [
"C408", # unnecessary-collection-call ( e.g. `dict(x=y)` => `{'x': y}`)
"D100", # Missing docstring in public module
"D101", # Missing docstring in public class
"D102", # Missing docstring in public method
"D103", # Missing docstring in public function
"D104", # Missing docstring in public package
"D105", # Missing docstring in magic method
"D106", # Missing docstring in public nested class
"D107", # Missing docstring in `__init__`
"PT003", # scope='function' is implied in @pytest.fixture()
"PT018", # Assertion should be broken down into multiple parts
"PT015", # Assertion always fails, replace with `pytest.fail()`
"RET504", # Unnecessary variable assignment before `return` statement
"RET506", # Unnecessary `elif` after `raise` statement
"RET505", # Unnecessary `elif` after `return` statement
"SIM118", # Use 'key in dict' instead of 'key in dict.keys()'
"SIM108", # Use ternary operator `d = 1 if b else 0` instead of if-else-block
"SIM103", # Checks for if statements that can be replaced with bool.
"TRY003", # Avoid specifying long messages outside the exception class
"S101", # Use of `assert` detected
"S311", # Standard pseudo-random generators are not suitable for cryptographic purposes
"TD002", # Missing author
"TD003", # Missing issue link
"PD901", # `df` is a bad variable name. Be kinder to your future self.
"D211", # `o-blank-line-before-class
"D213", # multi-line-summary-second-line
"D415", # First line should end with a period, question mark, or exclamation point
"D400", # First line should end with a period
"D203", # one-blank-line-before-class
"FBT001", # Boolean-typed positional argument in function definition
"FBT002", # Boolean default positional argument in function definition
"T201", # `print` found
"TC001", # Move application import x into a type-checking block
"TC002", # Move third-party import x into a type-checking block
"TC003", # Move standard library import x into a type-checking block
"ERA001", # Found commented-out code
"FIX002", # Line contains TODO, consider resolving the issue
# Textual goes hard on shadowing builtins so 🤷
"A002", # Function argument `id` is shadowing a Python builtin
"EM102", # Exception must not use an f-string literal, assign to variable first
"ANN401", # Dynamically typed expressions (typing.Any) are disallowed in `**kwargs`
"PLR2004", # Magic value used in comparison, consider replacing `1_000` with a constant variable
"PLR0912", # Too many branches (15 > 12)
"PLR0915", # Too many statements (52 > 50)
"C901", # `get_diff_summary` is too complex (11 > 10)
"SIM102", # `Use a single `if` statement instead of nested `if` statements
"G004", # Logging statement uses f-string
"EM101", # Exception must not use a string literal, assign to variable first
"PLR0913", # Too many arguments in function definition (9 > 5)
"TRY300", # Consider moving this statement to an `else` block
"TRY301", # Abstract `raise` to an inner function
"SIM114", # if-with-same-arms
"FIX004", # Line contains HACK, consider resolving the issue
"G003", # Logging statement uses `+`
"PERF401", # Use `list.extend` to create a transformed list
]
lint.unfixable = [
# Auto-fixing RUF100 often results in it auto removing the noqa statement,
# which might just be a typo. Best to leave it to the user to fix.
"RUF100", # Unused `noqa` directive / Unused blanket `noqa` directive
# Auto-fixing F841 results in e.g. `a = df["a"]` silently turning ino `df["a"]`
# Mega annoying, especially if running ruff against WIP code.
"F841", # Local variable `a` is assigned to but never used
# Auto-fixing PIE794 wipes an item from the class - would rather fix manually.
"PIE794", # duplicate-class-field-definition
# The autofix for this sets it to False 🫠🫠🫠🫠good God
"B905", # zip() without explicit `strict` parameter
]
[tool.ruff.lint.pydocstyle]
convention = "google" # Accepts: "google", "numpy", or "pep257".
[tool.ruff.lint.flake8-pytest-style]
parametrize-values-type = "tuple"
[tool.ruff.lint.flake8-unused-arguments]
ignore-variadic-names = true
[tool.ruff.lint.flake8-tidy-imports]
# Disallow all relative imports.
ban-relative-imports = "all"
[tool.uv.workspace]
members = ["blah/blah"]