feat: extract github-projects-client, generalize MCP server for any board#31
Merged
Conversation
There was a problem hiding this comment.
Pull request overview
This PR extracts a reusable github-projects-client Python library for GitHub Projects v2 and refactors existing tools (the filozzy-mcp MCP server, foc-pr-report, and github-project-export) to consume it, while adding a root test runner and accompanying specs/docs.
Changes:
- Added
github-projects-client/with REST/GraphQL helpers, compact item shaping, view URL resolution, and mutations. - Updated
filozzy-mcp,foc-pr-report, andgithub-project-exportto depend on/import from the shared client and added cross-package integration test runner. - Added a full specification package under
specs/003-generalize-mcp-client/describing the design, contracts, and migration.
Reviewed changes
Copilot reviewed 34 out of 40 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| specs/003-generalize-mcp-client/tasks.md | Task breakdown for extracting the shared client and migrating consumers. |
| specs/003-generalize-mcp-client/spec.md | Feature spec defining scenarios, requirements, and success criteria. |
| specs/003-generalize-mcp-client/research.md | Captures key implementation decisions (packaging, boundaries, config). |
| specs/003-generalize-mcp-client/quickstart.md | Setup/migration guide and repo layout after refactor. |
| specs/003-generalize-mcp-client/plan.md | Implementation plan and target repo/package structure. |
| specs/003-generalize-mcp-client/data-model.md | Defines entity shapes (BoardItem, MutationResult, etc.). |
| specs/003-generalize-mcp-client/contracts/shared-client-api.md | Contract for the new library’s public API. |
| specs/003-generalize-mcp-client/contracts/mcp-tools.md | Contract for MCP tool behavior/config/audit logging. |
| specs/003-generalize-mcp-client/checklists/requirements.md | Spec quality checklist for the feature. |
| scripts/test-all.sh | Root script to run pytest across multiple packages and summarize results. |
| github-projects-client/pyproject.toml | New package definition for the shared client. |
| github-projects-client/uv.lock | Lockfile for shared client package dependencies. |
| github-projects-client/README.md | Usage docs and API overview for the shared client. |
| github-projects-client/github_projects_client/init.py | Public re-exports for shared client API. |
| github-projects-client/github_projects_client/api.py | REST/GraphQL request helpers + pagination utilities. |
| github-projects-client/github_projects_client/fields.py | Field option enumeration via GraphQL. |
| github-projects-client/github_projects_client/items.py | Compact item shaping, listing, and item reference resolution. |
| github-projects-client/github_projects_client/views.py | View URL parsing and filter/field-order resolution. |
| github-projects-client/github_projects_client/mutations.py | Shared mutation logic to set field values by name. |
| github-projects-client/tests/init.py | Test package marker for shared client tests. |
| github-projects-client/tests/test_integration.py | Integration tests against live GitHub API for shared client. |
| github-project-export/pyproject.toml | Switch dependency from foc-pr-report to github-projects-client. |
| github-project-export/uv.lock | Lockfile updated for new shared client dependency. |
| github-project-export/github_project_export/rest_export.py | Updated imports to use shared client REST helpers. |
| foc_wg_pr_notifier.py | Updated imports to use new pr_enrichment module. |
| foc-pr-report/pyproject.toml | Adds dependency on github-projects-client and test config. |
| foc-pr-report/uv.lock | Lockfile updated for shared client + pytest dev deps. |
| foc-pr-report/foc_pr_report/cli.py | Uses pr_enrichment instead of the old client module. |
| foc-pr-report/foc_pr_report/report.py | Uses pr_enrichment.field_values_by_name after refactor. |
| foc-pr-report/foc_pr_report/pr_enrichment.py | New PR-specific module (reviewer enrichment + REST→GraphQL mapping). |
| foc-pr-report/foc_pr_report/foc_project14_client.py | Backward-compat shim re-exporting to shared client + pr_enrichment. |
| foc-pr-report/tests/init.py | Test package marker for foc-pr-report tests. |
| foc-pr-report/tests/test_integration.py | End-to-end integration test for the PR report pipeline. |
| filozzy-mcp/pyproject.toml | Switch dependency from foc-pr-report to github-projects-client. |
| filozzy-mcp/uv.lock | Lockfile updated for shared client dependency. |
| filozzy-mcp/filozzy_mcp/server.py | Reads board config from env and delegates to shared client; logs mutations. |
| filozzy-mcp/tests/test_integration.py | Integration tests updated to focus on MCP-layer behavior. |
| filozzy-mcp/README.md | Docs updated for env-based board config and shared-client architecture. |
| README.md | Root README updated to describe new packages and add test runner instructions. |
| CLAUDE.md | Notes active technologies relevant to this feature. |
Comments suppressed due to low confidence (3)
github-projects-client/github_projects_client/mutations.py:47
- The docstring contains mojibake characters ("���") in "No audit logging ��� that's...", which will render poorly and can cause encoding issues in downstream tooling. Replace with a normal dash/em dash and ensure the file is saved as UTF-8.
github-projects-client/github_projects_client/mutations.py:138 set_field_valuereturns a dict keyed withitemrather thanitem_ref, and error returns omititem_ref/fieldentirely. This conflicts with theMutationResultshape described in the spec/data-model and makes it harder for callers (including the MCP layer) to consistently log/handle failures. Align the result shape with the contract (e.g., always includeitem_ref,field,success, and eitherold_value/new_valueorerror).
filozzy-mcp/filozzy_mcp/server.py:504set_board_item_fieldonly logs successful mutations. For auditability/debugging, failed mutation attempts (item not found, field/option invalid, API errors) should also be recorded in the action log withresultreflecting the failure reason and withoutold_value/new_valuewhen unavailable.
if result.get("success"):
old = result.get("old_value", "")
new = result.get("new_value", "")
log_action(
tool="set_board_item_field",
params={
"org": GITHUB_ORG,
"project_number": GITHUB_PROJECT_NUMBER,
"item_ref": item_ref,
"field_name": field_name,
"value": value,
},
result="success",
old_value=old,
new_value=new,
)
return (
f"Updated {item_ref}: {field_name} "
f"{'from \"' + old + '\" ' if old else ''}"
f'to "{new}"'
)
else:
return f"Failed: {result.get('error', 'unknown error')}"
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
BigLep
added a commit
that referenced
this pull request
Apr 27, 2026
- Parse GITHUB_PROJECT_NUMBER defensively with clear error on invalid input - Document default values for GITHUB_ORG, GITHUB_PROJECT_NUMBER, BOARD_NAMES in mcp-tools.md contract - Remove verbose param from shared-client-api.md (MCP-layer concern only) - Fix corrupted box-drawing characters in quickstart.md and plan.md - Update audit log JSON example to match actual implementation schema Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Defines the feature spec for extracting a shared, board-agnostic client library from filozzy-mcp and foc_project14_client.py. Covers: - Three-layer responsibility boundaries (shared client / MCP adapter / external tools) - Current boundary violations to fix during refactor - First-class tool vs. external tool decisions - Board alias configuration for LLM routing - Cross-package test infrastructure requirements Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Phase 0 research (package structure, naming, extraction boundaries, test runner, config approach, migration strategy) and Phase 1 design (data model, shared client API contract, MCP tools contract, quickstart). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
46 tasks across 6 phases: setup, shared client extraction, MCP server generalization (MVP), cross-package test runner, foc-pr-report migration, and polish. Uses git mv to preserve file history where possible. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Create the shared client library package with pyproject.toml, hatchling build, and pytest config. No code yet — populated in the next phase. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract shared GitHub Projects v2 board logic from foc_project14_client.py and filozzy-mcp into a new ghprojects-client package. All functions are parameterized by org/project_number with no hardcoded defaults. - ghprojects-client: api.py, fields.py, items.py, views.py, mutations.py with 21 integration tests - filozzy-mcp server.py: reads GITHUB_ORG, GITHUB_PROJECT_NUMBER, BOARD_NAMES from env; imports from ghprojects_client; audit logging stays in MCP layer - foc-pr-report: PR-specific functions moved to pr_enrichment.py; foc_project14_client.py is now a thin backward-compat shim - github-project-export: imports directly from ghprojects_client - scripts/test-all.sh: cross-package test runner Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Move shared-client tests that only existed in filozzy-mcp into ghprojects-client (6 tests). Strip filozzy-mcp down to 2 MCP-layer- specific tests (docstring query validation). Zero overlap between the two test suites. Before: 21 + 29 = 50 tests (heavy duplication) After: 27 + 2 = 29 tests (no duplication) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add FilOzzy MCP Server and ghprojects-client sections to root README - Update filozzy-mcp README with env var docs and architecture section - Rewrite ghprojects-client README with full public API table - Add foc-pr-report integration test and pytest dev dependency - Mark all remaining spec tasks as complete Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Rename package directory, Python module, and all references for consistency with existing github-milestone-creator and github-project-export naming conventions. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Parse GITHUB_PROJECT_NUMBER defensively with clear error on invalid input - Document default values for GITHUB_ORG, GITHUB_PROJECT_NUMBER, BOARD_NAMES in mcp-tools.md contract - Remove verbose param from shared-client-api.md (MCP-layer concern only) - Fix corrupted box-drawing characters in quickstart.md and plan.md - Update audit log JSON example to match actual implementation schema Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Port fetch_pull_request_review_activity (renamed from fetch_pull_request_review_logins) with has_non_user_review return value into pr_enrichment.py, matching master's PR #33 changes - Update enrich_pull_items_with_submitted_reviewers to set _has_non_user_submitted_review on each PR item - Add backward-compat alias for old function name - Export fetch_pull_request_review_activity from shim - Fix test_lookup_by_short_ref: filter to org items since short refs expand using the default org Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
f9abf5d to
6c84654
Compare
3 tasks
Contributor
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
github-projects-client/— a standalone, reusable Python client for GitHub Projects v2 boards. No MCP dependency; purerequests-based. Context-efficient (~200-300 bytes per item vs ~8KB from GitHub's API).filozzy-mcp— the MCP server now reads org/project/board-names from environment variables instead of hardcoding FilOzone/Project 14. Works with any GitHub Projects v2 board.foc-pr-report— PR-specific logic extracted intopr_enrichment.py; shared board logic now comes fromgithub-projects-client. Backward-compat shim kept infoc_project14_client.py.github-project-export— now imports directly fromgithub-projects-client.scripts/test-all.shruns 30 integration tests across 3 packages (27 github-projects-client + 2 filozzy-mcp + 1 foc-pr-report).has_non_user_reviewreviewer tracking) into the extractedpr_enrichment.py.Architecture
Test plan
./scripts/test-all.sh— all 30 tests pass (27 + 2 + 1)set_board_item_fieldmutations work (Status, Cycle Theme)foc-pr-reportCLI produces correct markdown outputgithub-project-exportworks with new importsfoc_project14_client.pyresolved (kept shim, ported PR feat(foc-pr-report): triage-first ordering and table action hints #33 changes topr_enrichment.py)test_lookup_by_short_ref— filter to org-local items since short refs expand using default org🤖 Generated with Claude Code