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.
Files changed (96) hide show
  1. uk_parliament_mcp-1.1.0/.github/dependabot.yml +12 -0
  2. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/.github/workflows/ci.yml +11 -2
  3. uk_parliament_mcp-1.1.0/.pre-commit-config.yaml +14 -0
  4. uk_parliament_mcp-1.1.0/AGENTS.md +56 -0
  5. uk_parliament_mcp-1.1.0/CHANGELOG.md +61 -0
  6. uk_parliament_mcp-1.1.0/CLAUDE.md +294 -0
  7. uk_parliament_mcp-1.1.0/CONTRIBUTING.md +119 -0
  8. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/IMPLEMENTATION_PLAN.md +57 -2
  9. uk_parliament_mcp-1.1.0/IMPLEMENTATION_PLAN_IMPROVEMENTS.md +263 -0
  10. uk_parliament_mcp-1.1.0/IMPROVEMENTS.md +225 -0
  11. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/PKG-INFO +217 -188
  12. uk_parliament_mcp-1.1.0/PROMPT_build.md +57 -0
  13. uk_parliament_mcp-1.1.0/PROMPT_plan.md +63 -0
  14. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/README.md +215 -186
  15. uk_parliament_mcp-1.1.0/docs/IMPROVEMENT_PLAN.md +375 -0
  16. uk_parliament_mcp-1.1.0/docs/PHASE1_QUICK_WINS.md +106 -0
  17. uk_parliament_mcp-1.1.0/docs/PHASE2_CODE_QUALITY.md +237 -0
  18. uk_parliament_mcp-1.1.0/docs/PHASE3_TESTING.md +262 -0
  19. uk_parliament_mcp-1.1.0/docs/PHASE4_DOCUMENTATION.md +390 -0
  20. uk_parliament_mcp-1.1.0/docs/PHASE5_ARCHITECTURE.md +267 -0
  21. uk_parliament_mcp-1.1.0/loop.ps1 +81 -0
  22. uk_parliament_mcp-1.1.0/loop.sh +73 -0
  23. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/pyproject.toml +14 -1
  24. uk_parliament_mcp-1.1.0/specs/agent-guidance-spec.md +164 -0
  25. uk_parliament_mcp-1.1.0/specs/improvement-spec.md +54 -0
  26. uk_parliament_mcp-1.1.0/specs/v2-improvements-spec.md +228 -0
  27. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/__init__.py +1 -1
  28. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/__main__.py +1 -0
  29. uk_parliament_mcp-1.1.0/src/uk_parliament_mcp/config.py +20 -0
  30. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/http_client.py +79 -1
  31. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/server.py +8 -1
  32. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/tools/bills.py +2 -2
  33. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/tools/committees.py +2 -2
  34. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/tools/commons_votes.py +2 -2
  35. uk_parliament_mcp-1.1.0/src/uk_parliament_mcp/tools/composite.py +293 -0
  36. uk_parliament_mcp-1.1.0/src/uk_parliament_mcp/tools/core.py +880 -0
  37. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/tools/erskine_may.py +2 -2
  38. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/tools/hansard.py +2 -2
  39. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/tools/interests.py +2 -2
  40. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/tools/lords_votes.py +2 -2
  41. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/tools/members.py +2 -2
  42. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/tools/now.py +2 -2
  43. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/tools/oral_questions.py +2 -2
  44. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/tools/statutory_instruments.py +2 -2
  45. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/tools/treaties.py +2 -2
  46. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/tools/whatson.py +2 -2
  47. uk_parliament_mcp-1.1.0/src/uk_parliament_mcp/validators.py +58 -0
  48. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/tests/test_http_client.py +157 -0
  49. uk_parliament_mcp-1.1.0/tests/test_tools/test_bills.py +638 -0
  50. uk_parliament_mcp-1.1.0/tests/test_tools/test_committees.py +515 -0
  51. uk_parliament_mcp-1.1.0/tests/test_tools/test_commons_votes.py +382 -0
  52. uk_parliament_mcp-1.1.0/tests/test_tools/test_composite.py +217 -0
  53. uk_parliament_mcp-1.1.0/tests/test_tools/test_core.py +413 -0
  54. uk_parliament_mcp-1.1.0/tests/test_tools/test_erskine_may.py +109 -0
  55. uk_parliament_mcp-1.1.0/tests/test_tools/test_hansard.py +123 -0
  56. uk_parliament_mcp-1.1.0/tests/test_tools/test_interests.py +121 -0
  57. uk_parliament_mcp-1.1.0/tests/test_tools/test_lords_votes.py +420 -0
  58. uk_parliament_mcp-1.1.0/tests/test_tools/test_members.py +750 -0
  59. uk_parliament_mcp-1.1.0/tests/test_tools/test_now.py +87 -0
  60. uk_parliament_mcp-1.1.0/tests/test_tools/test_oral_questions.py +188 -0
  61. uk_parliament_mcp-1.1.0/tests/test_tools/test_statutory_instruments.py +168 -0
  62. uk_parliament_mcp-1.1.0/tests/test_tools/test_treaties.py +135 -0
  63. uk_parliament_mcp-1.1.0/tests/test_tools/test_whatson.py +182 -0
  64. uk_parliament_mcp-1.1.0/verify_readme_rendering.py +107 -0
  65. uk_parliament_mcp-1.0.0/AGENTS.md +0 -73
  66. uk_parliament_mcp-1.0.0/CLAUDE.md +0 -160
  67. uk_parliament_mcp-1.0.0/PROMPT_build.md +0 -119
  68. uk_parliament_mcp-1.0.0/PROMPT_plan.md +0 -80
  69. uk_parliament_mcp-1.0.0/loop.sh +0 -53
  70. uk_parliament_mcp-1.0.0/src/uk_parliament_mcp/tools/core.py +0 -28
  71. uk_parliament_mcp-1.0.0/tests/test_tools/test_core.py +0 -87
  72. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/.github/workflows/publish.yml +0 -0
  73. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/.gitignore +0 -0
  74. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/.python-version +0 -0
  75. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/config/claude_desktop_config.json.example +0 -0
  76. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/config/vscode_mcp_config.json.example +0 -0
  77. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/bills-api.json +0 -0
  78. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/committees-api.json +0 -0
  79. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/commonsvotes-api.json +0 -0
  80. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/erskinemay-api.json +0 -0
  81. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/hansard-api.json +0 -0
  82. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/interests-api.json +0 -0
  83. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/lordsvotes-api.json +0 -0
  84. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/members-api.json +0 -0
  85. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/oralquestions-api.json +0 -0
  86. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/parliamentnow-api.json +0 -0
  87. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/readme.md +0 -0
  88. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/statutoryinstruments-api.json +0 -0
  89. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/treaties-api.json +0 -0
  90. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/whatson-api.json +0 -0
  91. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/context/writtenquestions-api.json +0 -0
  92. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/specs/python-migration-spec.md +0 -0
  93. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/src/uk_parliament_mcp/tools/__init__.py +0 -0
  94. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/tests/__init__.py +0 -0
  95. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/tests/conftest.py +0 -0
  96. {uk_parliament_mcp-1.0.0 → uk_parliament_mcp-1.1.0}/tests/test_tools/__init__.py +0 -0
@@ -0,0 +1,12 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "pip"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+ open-pull-requests-limit: 5
8
+
9
+ - package-ecosystem: "github-actions"
10
+ directory: "/"
11
+ schedule:
12
+ interval: "weekly"
@@ -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
- - [ ] Final commit with Python-only project
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
- - C# reference: `OpenData.Mcp.Server/Tools/*.cs`
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)