uk-parliament-mcp 1.0.0__tar.gz → 1.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- uk_parliament_mcp-1.1.0/.github/dependabot.yml +12 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/.github/workflows/ci.yml +11 -2
- uk_parliament_mcp-1.1.0/.pre-commit-config.yaml +14 -0
- uk_parliament_mcp-1.1.0/AGENTS.md +56 -0
- uk_parliament_mcp-1.1.0/CHANGELOG.md +61 -0
- uk_parliament_mcp-1.1.0/CLAUDE.md +294 -0
- uk_parliament_mcp-1.1.0/CONTRIBUTING.md +119 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/IMPLEMENTATION_PLAN.md +57 -2
- uk_parliament_mcp-1.1.0/IMPLEMENTATION_PLAN_IMPROVEMENTS.md +263 -0
- uk_parliament_mcp-1.1.0/IMPROVEMENTS.md +225 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/PKG-INFO +217 -188
- uk_parliament_mcp-1.1.0/PROMPT_build.md +57 -0
- uk_parliament_mcp-1.1.0/PROMPT_plan.md +63 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/README.md +215 -186
- uk_parliament_mcp-1.1.0/docs/IMPROVEMENT_PLAN.md +375 -0
- uk_parliament_mcp-1.1.0/docs/PHASE1_QUICK_WINS.md +106 -0
- uk_parliament_mcp-1.1.0/docs/PHASE2_CODE_QUALITY.md +237 -0
- uk_parliament_mcp-1.1.0/docs/PHASE3_TESTING.md +262 -0
- uk_parliament_mcp-1.1.0/docs/PHASE4_DOCUMENTATION.md +390 -0
- uk_parliament_mcp-1.1.0/docs/PHASE5_ARCHITECTURE.md +267 -0
- uk_parliament_mcp-1.1.0/loop.ps1 +81 -0
- uk_parliament_mcp-1.1.0/loop.sh +73 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/pyproject.toml +14 -1
- uk_parliament_mcp-1.1.0/specs/agent-guidance-spec.md +164 -0
- uk_parliament_mcp-1.1.0/specs/improvement-spec.md +54 -0
- uk_parliament_mcp-1.1.0/specs/v2-improvements-spec.md +228 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/__init__.py +1 -1
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/__main__.py +1 -0
- uk_parliament_mcp-1.1.0/src/uk_parliament_mcp/config.py +20 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/http_client.py +79 -1
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/server.py +8 -1
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/tools/bills.py +2 -2
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/tools/committees.py +2 -2
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/tools/commons_votes.py +2 -2
- uk_parliament_mcp-1.1.0/src/uk_parliament_mcp/tools/composite.py +293 -0
- uk_parliament_mcp-1.1.0/src/uk_parliament_mcp/tools/core.py +880 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/tools/erskine_may.py +2 -2
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/tools/hansard.py +2 -2
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/tools/interests.py +2 -2
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/tools/lords_votes.py +2 -2
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/tools/members.py +2 -2
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/tools/now.py +2 -2
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/tools/oral_questions.py +2 -2
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/tools/statutory_instruments.py +2 -2
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/tools/treaties.py +2 -2
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/tools/whatson.py +2 -2
- uk_parliament_mcp-1.1.0/src/uk_parliament_mcp/validators.py +58 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/tests/test_http_client.py +157 -0
- uk_parliament_mcp-1.1.0/tests/test_tools/test_bills.py +638 -0
- uk_parliament_mcp-1.1.0/tests/test_tools/test_committees.py +515 -0
- uk_parliament_mcp-1.1.0/tests/test_tools/test_commons_votes.py +382 -0
- uk_parliament_mcp-1.1.0/tests/test_tools/test_composite.py +217 -0
- uk_parliament_mcp-1.1.0/tests/test_tools/test_core.py +413 -0
- uk_parliament_mcp-1.1.0/tests/test_tools/test_erskine_may.py +109 -0
- uk_parliament_mcp-1.1.0/tests/test_tools/test_hansard.py +123 -0
- uk_parliament_mcp-1.1.0/tests/test_tools/test_interests.py +121 -0
- uk_parliament_mcp-1.1.0/tests/test_tools/test_lords_votes.py +420 -0
- uk_parliament_mcp-1.1.0/tests/test_tools/test_members.py +750 -0
- uk_parliament_mcp-1.1.0/tests/test_tools/test_now.py +87 -0
- uk_parliament_mcp-1.1.0/tests/test_tools/test_oral_questions.py +188 -0
- uk_parliament_mcp-1.1.0/tests/test_tools/test_statutory_instruments.py +168 -0
- uk_parliament_mcp-1.1.0/tests/test_tools/test_treaties.py +135 -0
- uk_parliament_mcp-1.1.0/tests/test_tools/test_whatson.py +182 -0
- uk_parliament_mcp-1.1.0/verify_readme_rendering.py +107 -0
- uk_parliament_mcp-1.0.0/AGENTS.md +0 -73
- uk_parliament_mcp-1.0.0/CLAUDE.md +0 -160
- uk_parliament_mcp-1.0.0/PROMPT_build.md +0 -119
- uk_parliament_mcp-1.0.0/PROMPT_plan.md +0 -80
- uk_parliament_mcp-1.0.0/loop.sh +0 -53
- uk_parliament_mcp-1.0.0/src/uk_parliament_mcp/tools/core.py +0 -28
- uk_parliament_mcp-1.0.0/tests/test_tools/test_core.py +0 -87
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/.github/workflows/publish.yml +0 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/.gitignore +0 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/.python-version +0 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/config/claude_desktop_config.json.example +0 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/config/vscode_mcp_config.json.example +0 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/bills-api.json +0 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/committees-api.json +0 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/commonsvotes-api.json +0 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/erskinemay-api.json +0 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/hansard-api.json +0 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/interests-api.json +0 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/lordsvotes-api.json +0 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/members-api.json +0 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/oralquestions-api.json +0 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/parliamentnow-api.json +0 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/readme.md +0 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/statutoryinstruments-api.json +0 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/treaties-api.json +0 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/whatson-api.json +0 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/writtenquestions-api.json +0 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/specs/python-migration-spec.md +0 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/tools/__init__.py +0 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/tests/__init__.py +0 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/tests/conftest.py +0 -0
- {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/tests/test_tools/__init__.py +0 -0
|
@@ -20,6 +20,7 @@ jobs:
|
|
|
20
20
|
uses: actions/setup-python@v5
|
|
21
21
|
with:
|
|
22
22
|
python-version: ${{ matrix.python-version }}
|
|
23
|
+
cache: 'pip'
|
|
23
24
|
|
|
24
25
|
- name: Install dependencies
|
|
25
26
|
run: |
|
|
@@ -34,5 +35,13 @@ jobs:
|
|
|
34
35
|
- name: Type check with mypy
|
|
35
36
|
run: mypy src/
|
|
36
37
|
|
|
37
|
-
- name: Run tests
|
|
38
|
-
run: pytest
|
|
38
|
+
- name: Run tests with coverage
|
|
39
|
+
run: pytest --cov=uk_parliament_mcp --cov-report=xml --cov-report=term-missing
|
|
40
|
+
|
|
41
|
+
- name: Upload coverage to Codecov
|
|
42
|
+
uses: codecov/codecov-action@v4
|
|
43
|
+
with:
|
|
44
|
+
files: ./coverage.xml
|
|
45
|
+
fail_ci_if_error: false
|
|
46
|
+
env:
|
|
47
|
+
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
repos:
|
|
2
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
3
|
+
rev: v0.3.0
|
|
4
|
+
hooks:
|
|
5
|
+
- id: ruff
|
|
6
|
+
args: [--fix]
|
|
7
|
+
- id: ruff-format
|
|
8
|
+
|
|
9
|
+
- repo: https://github.com/pre-commit/mirrors-mypy
|
|
10
|
+
rev: v1.8.0
|
|
11
|
+
hooks:
|
|
12
|
+
- id: mypy
|
|
13
|
+
additional_dependencies: [types-all]
|
|
14
|
+
args: [--strict]
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# AGENTS.md - Operational Guide
|
|
2
|
+
|
|
3
|
+
Keep this file under 60 lines. It's loaded every iteration.
|
|
4
|
+
|
|
5
|
+
## Build Commands
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Install dependencies (dev mode)
|
|
9
|
+
pip install -e ".[dev]"
|
|
10
|
+
|
|
11
|
+
# Run the MCP server
|
|
12
|
+
python -m uk_parliament_mcp
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Test Commands
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
pytest # Run all tests
|
|
19
|
+
pytest tests/test_tools/ # Run tool tests only
|
|
20
|
+
pytest --cov=uk_parliament_mcp # Run with coverage
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Validation (run before committing)
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
ruff check src/ # Lint check
|
|
27
|
+
ruff format --check src/ # Format check
|
|
28
|
+
mypy src/ # Type check
|
|
29
|
+
pytest # Tests
|
|
30
|
+
|
|
31
|
+
# All at once:
|
|
32
|
+
ruff check src/ && ruff format --check src/ && mypy src/ && pytest
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Fixing Issues
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
ruff check src/ --fix # Auto-fix lint issues
|
|
39
|
+
ruff format src/ # Auto-format code
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Project Notes
|
|
43
|
+
|
|
44
|
+
- Python 3.11+ required
|
|
45
|
+
- Tool descriptions use semantic format: `Action | Keywords | Use case | Returns`
|
|
46
|
+
- House IDs: 1 = Commons, 2 = Lords
|
|
47
|
+
- Date format: YYYY-MM-DD
|
|
48
|
+
- API base URLs should be in `src/uk_parliament_mcp/config.py` (after Phase 2.1)
|
|
49
|
+
- Test files mirror source structure: `tools/members.py` -> `test_tools/test_members.py`
|
|
50
|
+
|
|
51
|
+
## Key Files
|
|
52
|
+
|
|
53
|
+
- `docs/IMPROVEMENT_PLAN.md` - Master improvement plan
|
|
54
|
+
- `docs/PHASE*.md` - Detailed phase specifications
|
|
55
|
+
- `IMPLEMENTATION_PLAN_IMPROVEMENTS.md` - Current task tracking
|
|
56
|
+
- `CLAUDE.md` - Project documentation for Claude Code
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.1.0] - 2026-02-03
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Centralized API configuration in `config.py`
|
|
12
|
+
- TypedDict for HTTP client response types
|
|
13
|
+
- Expanded test coverage for all tool modules
|
|
14
|
+
- pytest-cov for code coverage tracking
|
|
15
|
+
- CHANGELOG.md and CONTRIBUTING.md
|
|
16
|
+
- README badges (PyPI version, Python 3.11+, MIT License, CI status)
|
|
17
|
+
- README table of contents
|
|
18
|
+
- Configuration decision matrix in README
|
|
19
|
+
- Collapsible example prompt sections in README
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
- Restructured README with improved organization and navigation
|
|
23
|
+
- Corrected tool count from 94 to 92 in all documentation
|
|
24
|
+
- Safer dictionary access patterns in composite tools
|
|
25
|
+
|
|
26
|
+
### Removed
|
|
27
|
+
- Unused tenacity dependency
|
|
28
|
+
|
|
29
|
+
## [1.0.1] - 2026-02-01
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
- Server-level instructions for automatic context via MCP `instructions` parameter
|
|
33
|
+
- Composite tools documentation in CLAUDE.md
|
|
34
|
+
- Composite tools for common workflows (`get_mp_profile`, `check_mp_vote`, `get_bill_overview`, `get_committee_summary`)
|
|
35
|
+
- Agent guidance system with `/parliament` MCP prompt
|
|
36
|
+
- `parliament_guide()` and `parliament_workflow()` tools for navigating available tools
|
|
37
|
+
|
|
38
|
+
### Changed
|
|
39
|
+
- Improved documentation clarity in CLAUDE.md
|
|
40
|
+
- Enhanced LLM efficiency with high-level composite tools
|
|
41
|
+
|
|
42
|
+
### Fixed
|
|
43
|
+
- Getting Started section references to configuration steps
|
|
44
|
+
|
|
45
|
+
## [1.0.0] - 2026-01-28
|
|
46
|
+
|
|
47
|
+
### Added
|
|
48
|
+
- Initial Python release of UK Parliament MCP Server
|
|
49
|
+
- 92 tools covering 15 Parliament APIs (members, bills, votes, committees, Hansard, etc.)
|
|
50
|
+
- Support for Claude Desktop and VS Code via MCP protocol
|
|
51
|
+
- HTTP client with automatic retry logic and timeout protection
|
|
52
|
+
- Comprehensive documentation in CLAUDE.md and README.md
|
|
53
|
+
- CI/CD pipeline with GitHub Actions (linting, type checking, tests)
|
|
54
|
+
- PyPI publishing via Trusted Publishing
|
|
55
|
+
- Test infrastructure with pytest and pytest-asyncio
|
|
56
|
+
- Type checking with mypy
|
|
57
|
+
- Code quality enforcement with ruff
|
|
58
|
+
|
|
59
|
+
### Changed
|
|
60
|
+
- Migrated from C# implementation to Python 3.11+
|
|
61
|
+
- Adopted FastMCP framework for simplified MCP server development
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
# CLAUDE.md
|
|
2
|
+
|
|
3
|
+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
|
|
4
|
+
|
|
5
|
+
## Project Overview
|
|
6
|
+
|
|
7
|
+
UK Parliament MCP Server - A Model Context Protocol server that bridges AI assistants with official UK Parliament data APIs. Built with Python 3.11+, it provides 92 tools covering MPs/Lords, bills, votes, committees, Hansard, and more.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
# From PyPI (recommended)
|
|
13
|
+
pip install uk-parliament-mcp
|
|
14
|
+
|
|
15
|
+
# Or run without installing
|
|
16
|
+
uvx uk-parliament-mcp
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Development Setup
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Create virtual environment and install dependencies
|
|
23
|
+
python -m venv .venv
|
|
24
|
+
source .venv/bin/activate # Linux/Mac
|
|
25
|
+
# .venv\Scripts\activate # Windows
|
|
26
|
+
|
|
27
|
+
pip install -e ".[dev]"
|
|
28
|
+
|
|
29
|
+
# Run the MCP server (stdio transport)
|
|
30
|
+
python -m uk_parliament_mcp
|
|
31
|
+
|
|
32
|
+
# Run tests
|
|
33
|
+
pytest
|
|
34
|
+
|
|
35
|
+
# Type checking
|
|
36
|
+
mypy src/
|
|
37
|
+
|
|
38
|
+
# Linting
|
|
39
|
+
ruff check src/
|
|
40
|
+
ruff format src/
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## CI/CD
|
|
44
|
+
|
|
45
|
+
GitHub Actions workflows in `.github/workflows/`:
|
|
46
|
+
|
|
47
|
+
- **ci.yml**: Runs on push/PR - linting (ruff), type checking (mypy), tests (pytest)
|
|
48
|
+
- **publish.yml**: Runs on GitHub Release - builds and publishes to PyPI via Trusted Publishing
|
|
49
|
+
|
|
50
|
+
**Release process:**
|
|
51
|
+
1. Update version in `src/uk_parliament_mcp/__init__.py`
|
|
52
|
+
2. Commit and push
|
|
53
|
+
3. Create GitHub Release with tag (e.g., `v1.0.1`)
|
|
54
|
+
4. Package auto-publishes to PyPI
|
|
55
|
+
|
|
56
|
+
## Architecture
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
AI Assistant ──(MCP/stdio)──> uk_parliament_mcp ──(HTTP)──> UK Parliament APIs
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
**Key Components:**
|
|
63
|
+
|
|
64
|
+
- **`__main__.py`**: Entry point. Configures logging to stderr (stdout reserved for MCP protocol), creates and runs the FastMCP server.
|
|
65
|
+
|
|
66
|
+
- **`server.py`**: FastMCP server setup. Creates the MCP server with server-level instructions and registers all tool modules.
|
|
67
|
+
|
|
68
|
+
- **`http_client.py`**: HTTP client with retry logic. Provides:
|
|
69
|
+
- HTTP request handling with 3-retry exponential backoff
|
|
70
|
+
- 30-second timeout protection
|
|
71
|
+
- URL building with parameter filtering (`build_url`)
|
|
72
|
+
- Consistent response format: `{url, data}` or `{url, error, statusCode}`
|
|
73
|
+
|
|
74
|
+
- **`tools/*.py`**: 15 tool modules (92 total tools) each targeting a specific Parliament API:
|
|
75
|
+
| Module | API Domain | Purpose |
|
|
76
|
+
|--------|------------|---------|
|
|
77
|
+
| composite.py | Multiple APIs | High-level tools combining multiple API calls |
|
|
78
|
+
| members.py | members-api.parliament.uk | MPs, Lords, constituencies, parties |
|
|
79
|
+
| bills.py | bills-api.parliament.uk | Legislation, amendments, stages |
|
|
80
|
+
| commons_votes.py | commonsvotes-api.parliament.uk | Commons divisions |
|
|
81
|
+
| lords_votes.py | lordsvotes-api.parliament.uk | Lords divisions |
|
|
82
|
+
| committees.py | committees-api.parliament.uk | Committee info, evidence |
|
|
83
|
+
| hansard.py | hansard-api.parliament.uk | Parliamentary record |
|
|
84
|
+
| oral_questions.py | oralquestionsandmotions-api.parliament.uk | EDMs, questions |
|
|
85
|
+
| interests.py | interests-api.parliament.uk | Register of interests |
|
|
86
|
+
| now.py | now-api.parliament.uk | Live chamber activity |
|
|
87
|
+
| whatson.py | whatson-api.parliament.uk | Calendar, sessions |
|
|
88
|
+
| statutory_instruments.py | statutoryinstruments-api.parliament.uk | Acts, SIs |
|
|
89
|
+
| treaties.py | treaties-api.parliament.uk | International treaties |
|
|
90
|
+
| erskine_may.py | erskinemay-api.parliament.uk | Procedure rules |
|
|
91
|
+
| core.py | N/A | Session management & agent guidance |
|
|
92
|
+
|
|
93
|
+
- **`context/`**: OpenAPI spec JSON files for each Parliament API (reference documentation)
|
|
94
|
+
|
|
95
|
+
## Adding New Tools
|
|
96
|
+
|
|
97
|
+
Follow the established pattern in any `tools/*.py` file:
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
"""New API tools for [description]."""
|
|
101
|
+
from urllib.parse import quote
|
|
102
|
+
|
|
103
|
+
from mcp.server.fastmcp import FastMCP
|
|
104
|
+
|
|
105
|
+
from uk_parliament_mcp.http_client import build_url, get_result
|
|
106
|
+
|
|
107
|
+
NEW_API_BASE = "https://api.parliament.uk"
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def register_tools(mcp: FastMCP) -> None:
|
|
111
|
+
"""Register new tools with the MCP server."""
|
|
112
|
+
|
|
113
|
+
@mcp.tool()
|
|
114
|
+
async def get_something(param: str) -> str:
|
|
115
|
+
"""Action | keywords, synonyms | Use case | Returns format
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
param: Description of the parameter.
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
Description of what is returned.
|
|
122
|
+
"""
|
|
123
|
+
url = f"{NEW_API_BASE}/endpoint?param={quote(param)}"
|
|
124
|
+
return await get_result(url)
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Tool descriptions use a 4-part semantic format: `Action | Keywords | Use case | Returns`
|
|
128
|
+
|
|
129
|
+
Then register in `server.py`:
|
|
130
|
+
```python
|
|
131
|
+
from uk_parliament_mcp.tools import new_api
|
|
132
|
+
# ...
|
|
133
|
+
new_api.register_tools(mcp)
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Key Conventions
|
|
137
|
+
|
|
138
|
+
- **House IDs**: 1 = Commons, 2 = Lords
|
|
139
|
+
- **Date format**: YYYY-MM-DD throughout
|
|
140
|
+
- **Pagination**: `skip`/`take` parameters where supported
|
|
141
|
+
- All tools are read-only and idempotent
|
|
142
|
+
- Raw JSON responses from Parliament APIs are passed through (not transformed)
|
|
143
|
+
- Use `build_url(base, params)` for URL construction with parameter filtering
|
|
144
|
+
- Use `await get_result(url)` for HTTP requests with retry logic
|
|
145
|
+
|
|
146
|
+
## Server Instructions (Automatic Context)
|
|
147
|
+
|
|
148
|
+
The server provides automatic context to MCP clients via the `instructions` parameter in FastMCP. This means:
|
|
149
|
+
|
|
150
|
+
- **No initialization required**: Clients receive guidance during MCP handshake without needing to call `hello_parliament()` or `/parliament` first
|
|
151
|
+
- **Automatic behavior**: Per MCP spec, clients may add these instructions to the system prompt
|
|
152
|
+
- **Consistent sessions**: Every session starts with proper guidance about data sources and citation requirements
|
|
153
|
+
|
|
154
|
+
The instructions use the same `SYSTEM_PROMPT` from `core.py`, ensuring consistency across all initialization methods.
|
|
155
|
+
|
|
156
|
+
**How clients receive context:**
|
|
157
|
+
1. Client connects to MCP server
|
|
158
|
+
2. Server responds with `instructions` in initialize response
|
|
159
|
+
3. Client incorporates instructions (implementation varies by client)
|
|
160
|
+
4. Assistant automatically knows to use Parliament tools and cite sources
|
|
161
|
+
|
|
162
|
+
## Agent Skill (MCP Prompt)
|
|
163
|
+
|
|
164
|
+
The server also provides a `/parliament` agent skill that appears in the "/" command menu in MCP clients like Claude Desktop:
|
|
165
|
+
|
|
166
|
+
### `/parliament` (or `parliament` prompt)
|
|
167
|
+
Initialize a UK Parliament research session. Invocable as a slash command in Claude Desktop.
|
|
168
|
+
|
|
169
|
+
**Parameters:**
|
|
170
|
+
- `topic` (optional) - Jump directly to detailed guidance for a specific domain
|
|
171
|
+
|
|
172
|
+
**Example usage in Claude Desktop:**
|
|
173
|
+
```
|
|
174
|
+
/parliament # Start session with quick reference
|
|
175
|
+
/parliament members # Start session + detailed members guidance
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
This prompt is separate from the guidance **tools** below - prompts appear in the "/" menu and provide session context, while tools are called explicitly during research.
|
|
179
|
+
|
|
180
|
+
## Composite Tools
|
|
181
|
+
|
|
182
|
+
High-level tools that combine multiple API calls for common research tasks. Use these first for efficiency:
|
|
183
|
+
|
|
184
|
+
### `get_mp_profile(name)`
|
|
185
|
+
Get comprehensive MP/Lord profile in one call. Combines member search + biography + interests + voting.
|
|
186
|
+
- Returns: Basic info, biography, registered interests, recent votes
|
|
187
|
+
- Example: `get_mp_profile("Keir Starmer")`
|
|
188
|
+
|
|
189
|
+
### `check_mp_vote(mp_name, topic)`
|
|
190
|
+
Check how an MP voted on a specific topic. Combines member search + division lookup.
|
|
191
|
+
- Returns: MP info and divisions on the topic where they voted
|
|
192
|
+
- Example: `check_mp_vote("Boris Johnson", "climate")`
|
|
193
|
+
|
|
194
|
+
### `get_bill_overview(search_term)`
|
|
195
|
+
Get comprehensive bill overview. Combines bill search + details + stages + publications.
|
|
196
|
+
- Returns: Bill details, legislative stages, associated documents
|
|
197
|
+
- Example: `get_bill_overview("Online Safety")`
|
|
198
|
+
|
|
199
|
+
### `get_committee_summary(topic)`
|
|
200
|
+
Get comprehensive committee summary. Combines committee search + details + evidence + publications.
|
|
201
|
+
- Returns: Committee info, witness testimonies, written submissions, reports
|
|
202
|
+
- Example: `get_committee_summary("Treasury")`
|
|
203
|
+
|
|
204
|
+
## Agent Guidance Tools
|
|
205
|
+
|
|
206
|
+
The server also includes guidance **tools** to help AI assistants navigate the 92 available tools:
|
|
207
|
+
|
|
208
|
+
### `hello_parliament()`
|
|
209
|
+
Initialize a parliamentary research session (optional with server instructions). Returns:
|
|
210
|
+
- System prompt with data source transparency requirements
|
|
211
|
+
- Quick reference of all tool categories with entry points
|
|
212
|
+
- Key conventions (house IDs, date formats, pagination)
|
|
213
|
+
|
|
214
|
+
### `goodbye_parliament()`
|
|
215
|
+
End the parliamentary session and restore normal assistant behavior.
|
|
216
|
+
|
|
217
|
+
### `parliament_guide(topic)`
|
|
218
|
+
Get detailed guidance for a specific domain. Available topics:
|
|
219
|
+
- `composite` - 4 high-level tools combining multiple API calls
|
|
220
|
+
- `members` - 25 tools for MPs, Lords, constituencies, parties
|
|
221
|
+
- `bills` - 21 tools for legislation, amendments, stages
|
|
222
|
+
- `votes` - 10 tools for Commons and Lords divisions
|
|
223
|
+
- `committees` - 12 tools for committee info, meetings, evidence
|
|
224
|
+
- `hansard` - Parliamentary record search
|
|
225
|
+
- `questions` - EDMs, oral questions
|
|
226
|
+
- `interests` - Register of Interests
|
|
227
|
+
- `live` - Current activity, calendar (now + whatson)
|
|
228
|
+
- `legislation` - SIs, treaties
|
|
229
|
+
- `procedures` - Erskine May, bill types, stage definitions
|
|
230
|
+
- `all` - Condensed reference of all 92 tools
|
|
231
|
+
- `conventions` - Date formats, house IDs, pagination
|
|
232
|
+
- `workflows` - Overview of common research patterns
|
|
233
|
+
|
|
234
|
+
### `parliament_workflow(query)`
|
|
235
|
+
Get step-by-step workflow for a research task. Matches queries to predefined patterns:
|
|
236
|
+
- "How did my MP vote on X?" → MP voting workflow
|
|
237
|
+
- "Track bill progress" → Bill tracking workflow
|
|
238
|
+
- "What committee examined X?" → Committee research workflow
|
|
239
|
+
- "Does MP have conflicts of interest?" → Interests workflow
|
|
240
|
+
- "What's happening now?" → Live activity workflow
|
|
241
|
+
- And more (backgrounds, Hansard, elections, EDMs, treaties)
|
|
242
|
+
|
|
243
|
+
Example usage:
|
|
244
|
+
```
|
|
245
|
+
# Start session
|
|
246
|
+
hello_parliament()
|
|
247
|
+
|
|
248
|
+
# Get detailed guidance
|
|
249
|
+
parliament_guide("members")
|
|
250
|
+
|
|
251
|
+
# Plan a research task
|
|
252
|
+
parliament_workflow("How did my MP vote on climate?")
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## Dependencies
|
|
256
|
+
|
|
257
|
+
- mcp (>=1.0.0) - Anthropic's official MCP library
|
|
258
|
+
- httpx (>=0.27.0) - Async HTTP client
|
|
259
|
+
- tenacity (>=8.2.0) - Retry logic (available but manual retry used)
|
|
260
|
+
|
|
261
|
+
### Dev Dependencies
|
|
262
|
+
|
|
263
|
+
- pytest (>=8.0.0) - Testing
|
|
264
|
+
- pytest-asyncio (>=0.23.0) - Async test support
|
|
265
|
+
- pytest-httpx (>=0.30.0) - HTTP mocking
|
|
266
|
+
- ruff (>=0.3.0) - Linting and formatting
|
|
267
|
+
- mypy (>=1.8.0) - Type checking
|
|
268
|
+
|
|
269
|
+
## Project Structure
|
|
270
|
+
|
|
271
|
+
```
|
|
272
|
+
src/uk_parliament_mcp/
|
|
273
|
+
├── __init__.py
|
|
274
|
+
├── __main__.py # Entry point
|
|
275
|
+
├── server.py # FastMCP server setup
|
|
276
|
+
├── http_client.py # HTTP client with retry
|
|
277
|
+
└── tools/
|
|
278
|
+
├── __init__.py
|
|
279
|
+
├── core.py # Session management & guidance (4 tools)
|
|
280
|
+
├── composite.py # High-level composite tools (4 tools)
|
|
281
|
+
├── members.py # Member tools (25 tools)
|
|
282
|
+
├── bills.py # Bills tools (21 tools)
|
|
283
|
+
├── committees.py # Committees tools (12 tools)
|
|
284
|
+
├── commons_votes.py # Commons votes (5 tools)
|
|
285
|
+
├── lords_votes.py # Lords votes (5 tools)
|
|
286
|
+
├── hansard.py # Hansard (1 tool)
|
|
287
|
+
├── oral_questions.py # Questions (3 tools)
|
|
288
|
+
├── interests.py # Interests (3 tools)
|
|
289
|
+
├── now.py # Live activity (2 tools)
|
|
290
|
+
├── whatson.py # Calendar (3 tools)
|
|
291
|
+
├── statutory_instruments.py # SIs (2 tools)
|
|
292
|
+
├── treaties.py # Treaties (1 tool)
|
|
293
|
+
└── erskine_may.py # Procedure (1 tool)
|
|
294
|
+
```
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Contributing to UK Parliament MCP
|
|
2
|
+
|
|
3
|
+
Thank you for your interest in contributing! This document provides guidelines and instructions.
|
|
4
|
+
|
|
5
|
+
## Development Setup
|
|
6
|
+
|
|
7
|
+
1. **Clone the repository:**
|
|
8
|
+
```bash
|
|
9
|
+
git clone https://github.com/ChrisBrooksbank/uk-parliament-mcp-lab.git
|
|
10
|
+
cd uk-parliament-mcp-lab
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
2. **Create virtual environment:**
|
|
14
|
+
```bash
|
|
15
|
+
python -m venv .venv
|
|
16
|
+
source .venv/bin/activate # Linux/Mac
|
|
17
|
+
.venv\Scripts\activate # Windows
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
3. **Install with dev dependencies:**
|
|
21
|
+
```bash
|
|
22
|
+
pip install -e ".[dev]"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Code Style
|
|
26
|
+
|
|
27
|
+
We use automated tools to maintain consistency:
|
|
28
|
+
|
|
29
|
+
- **Ruff** for linting and formatting
|
|
30
|
+
- **MyPy** for type checking
|
|
31
|
+
|
|
32
|
+
Run before committing:
|
|
33
|
+
```bash
|
|
34
|
+
ruff check src/
|
|
35
|
+
ruff format src/
|
|
36
|
+
mypy src/
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## Adding New Tools
|
|
40
|
+
|
|
41
|
+
1. Create or update a module in `src/uk_parliament_mcp/tools/`
|
|
42
|
+
2. Follow the established pattern:
|
|
43
|
+
|
|
44
|
+
```python
|
|
45
|
+
"""Description of API tools."""
|
|
46
|
+
from mcp.server.fastmcp import FastMCP
|
|
47
|
+
from uk_parliament_mcp.config import API_BASE
|
|
48
|
+
from uk_parliament_mcp.http_client import build_url, get_result
|
|
49
|
+
|
|
50
|
+
def register_tools(mcp: FastMCP) -> None:
|
|
51
|
+
"""Register tools with the MCP server."""
|
|
52
|
+
|
|
53
|
+
@mcp.tool()
|
|
54
|
+
async def my_new_tool(param: str) -> str:
|
|
55
|
+
"""Action | keywords | Use case | Returns format
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
param: Description.
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
What is returned.
|
|
62
|
+
"""
|
|
63
|
+
url = f"{API_BASE}/endpoint?param={param}"
|
|
64
|
+
return await get_result(url)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
3. Register in `server.py`:
|
|
68
|
+
```python
|
|
69
|
+
from uk_parliament_mcp.tools import my_module
|
|
70
|
+
my_module.register_tools(mcp)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
4. Add tests in `tests/test_tools/test_my_module.py`
|
|
74
|
+
|
|
75
|
+
5. Update documentation in `CLAUDE.md`
|
|
76
|
+
|
|
77
|
+
## Testing
|
|
78
|
+
|
|
79
|
+
Run the test suite:
|
|
80
|
+
```bash
|
|
81
|
+
pytest
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
With coverage:
|
|
85
|
+
```bash
|
|
86
|
+
pytest --cov=uk_parliament_mcp --cov-report=term-missing
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
**Requirements:**
|
|
90
|
+
- All new tools must have tests
|
|
91
|
+
- Tests should verify URL construction
|
|
92
|
+
- Target 80%+ coverage
|
|
93
|
+
|
|
94
|
+
## Pull Request Process
|
|
95
|
+
|
|
96
|
+
1. Create a feature branch from `main`
|
|
97
|
+
2. Make your changes
|
|
98
|
+
3. Ensure all checks pass:
|
|
99
|
+
```bash
|
|
100
|
+
ruff check src/
|
|
101
|
+
ruff format --check src/
|
|
102
|
+
mypy src/
|
|
103
|
+
pytest
|
|
104
|
+
```
|
|
105
|
+
4. Update documentation if needed
|
|
106
|
+
5. Submit PR with clear description
|
|
107
|
+
|
|
108
|
+
## Reporting Issues
|
|
109
|
+
|
|
110
|
+
Please include:
|
|
111
|
+
- Python version
|
|
112
|
+
- OS and version
|
|
113
|
+
- Steps to reproduce
|
|
114
|
+
- Expected vs actual behavior
|
|
115
|
+
- Error messages if applicable
|
|
116
|
+
|
|
117
|
+
## Questions?
|
|
118
|
+
|
|
119
|
+
Open an issue with the "question" label.
|
|
@@ -183,7 +183,7 @@
|
|
|
183
183
|
|
|
184
184
|
- [x] Delete `OpenData.Mcp.Server/` folder
|
|
185
185
|
- [x] Delete `OpenDataMcpServer.sln`
|
|
186
|
-
- [
|
|
186
|
+
- [x] Final commit with Python-only project (03ca315)
|
|
187
187
|
|
|
188
188
|
---
|
|
189
189
|
|
|
@@ -223,5 +223,60 @@
|
|
|
223
223
|
## Reference Files
|
|
224
224
|
|
|
225
225
|
- Migration spec: `specs/python-migration-spec.md`
|
|
226
|
-
-
|
|
226
|
+
- Agent guidance spec: `specs/agent-guidance-spec.md`
|
|
227
|
+
- Improvement spec: `specs/improvement-spec.md`
|
|
228
|
+
- **v2.0 Improvements spec: `specs/v2-improvements-spec.md`**
|
|
227
229
|
- Operational guide: `AGENTS.md`
|
|
230
|
+
|
|
231
|
+
---
|
|
232
|
+
|
|
233
|
+
## v2.0 Improvements (spec: v2-improvements-spec.md)
|
|
234
|
+
|
|
235
|
+
### Phase 1: Foundation (P1)
|
|
236
|
+
|
|
237
|
+
- [ ] Create `normalize_house()` helper in validators.py (spec: 1.1)
|
|
238
|
+
- [ ] Update `parties_list_by_house()` to use normalize_house (spec: 1.1)
|
|
239
|
+
- [ ] Update `search_members()` house parameter (spec: 1.1)
|
|
240
|
+
- [ ] Update `get_member_registered_interests()` house parameter (spec: 1.1)
|
|
241
|
+
- [ ] Update `get_member_voting()` house parameter (spec: 1.1)
|
|
242
|
+
- [ ] Update `search_hansard()` house parameter (spec: 1.1)
|
|
243
|
+
- [ ] Update `search_calendar()` house parameter (spec: 1.1)
|
|
244
|
+
- [ ] Update `get_non_sitting_days()` house parameter (spec: 1.1)
|
|
245
|
+
- [ ] Update `get_sittings()` house parameter (spec: 1.1)
|
|
246
|
+
- [ ] Enable caching for `bill_types()` (spec: 1.2)
|
|
247
|
+
- [ ] Enable caching for `bill_stages()` (spec: 1.2)
|
|
248
|
+
- [ ] Enable caching for `parties_list_by_house()` (spec: 1.2)
|
|
249
|
+
- [ ] Enable caching for `get_publication_types()` (spec: 1.2)
|
|
250
|
+
- [ ] Enable caching for `get_answering_bodies()` (spec: 1.2)
|
|
251
|
+
- [ ] Add `validate_date()` function (spec: 1.3)
|
|
252
|
+
- [ ] Add `validate_positive_int()` function (spec: 1.3)
|
|
253
|
+
- [ ] Add `validate_pagination()` function (spec: 1.3)
|
|
254
|
+
- [ ] Apply validation to tools with date parameters (spec: 1.3)
|
|
255
|
+
- [ ] Apply validation to tools with ID parameters (spec: 1.3)
|
|
256
|
+
|
|
257
|
+
### Phase 2: Discoverability (P2)
|
|
258
|
+
|
|
259
|
+
- [ ] Add cross-references to members.py docstrings (spec: 2.1)
|
|
260
|
+
- [ ] Add cross-references to bills.py docstrings (spec: 2.1)
|
|
261
|
+
- [ ] Add cross-references to committees.py docstrings (spec: 2.1)
|
|
262
|
+
- [ ] Add "Uses" section to composite.py tools (spec: 2.2)
|
|
263
|
+
|
|
264
|
+
### Phase 3: New Capabilities (P2)
|
|
265
|
+
|
|
266
|
+
- [ ] Implement `compare_mp_voting()` composite tool (spec: 3.1)
|
|
267
|
+
- [ ] Implement `search_parliament()` aggregated search (spec: 3.2)
|
|
268
|
+
- [ ] Implement `get_bills_by_sponsor()` tool (spec: 3.3)
|
|
269
|
+
- [ ] Add tests for new composite tools
|
|
270
|
+
|
|
271
|
+
### Phase 4: Code Quality (P3)
|
|
272
|
+
|
|
273
|
+
- [ ] Standardize oral_questions.py docstrings (spec: 4.1)
|
|
274
|
+
- [ ] Standardize erskine_may.py docstrings (spec: 4.1)
|
|
275
|
+
- [ ] Standardize interests.py docstrings (spec: 4.1)
|
|
276
|
+
- [ ] Add error recovery guidance to composite tools (spec: 4.2)
|
|
277
|
+
|
|
278
|
+
### Phase 5: Project Quality (P4)
|
|
279
|
+
|
|
280
|
+
- [ ] Create LICENSE file (spec: 5.1)
|
|
281
|
+
- [ ] Create CHANGELOG.md (spec: 5.2)
|
|
282
|
+
- [ ] Create .pre-commit-config.yaml (spec: 5.3)
|