speechwire-mcp 0.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.
- speechwire_mcp-0.1.0/.env.example +6 -0
- speechwire_mcp-0.1.0/.github/copilot-instructions.md +127 -0
- speechwire_mcp-0.1.0/.github/workflows/ci.yml +22 -0
- speechwire_mcp-0.1.0/.github/workflows/publish.yml +87 -0
- speechwire_mcp-0.1.0/.gitignore +36 -0
- speechwire_mcp-0.1.0/LICENSE +21 -0
- speechwire_mcp-0.1.0/PKG-INFO +93 -0
- speechwire_mcp-0.1.0/README.md +64 -0
- speechwire_mcp-0.1.0/pyproject.toml +55 -0
- speechwire_mcp-0.1.0/src/speechwire_mcp/__init__.py +37 -0
- speechwire_mcp-0.1.0/src/speechwire_mcp/__main__.py +5 -0
- speechwire_mcp-0.1.0/src/speechwire_mcp/client.py +411 -0
- speechwire_mcp-0.1.0/src/speechwire_mcp/judges/__init__.py +23 -0
- speechwire_mcp-0.1.0/src/speechwire_mcp/judges/client.py +424 -0
- speechwire_mcp-0.1.0/src/speechwire_mcp/judges/parsers.py +533 -0
- speechwire_mcp-0.1.0/src/speechwire_mcp/login/__init__.py +6 -0
- speechwire_mcp-0.1.0/src/speechwire_mcp/login/client.py +65 -0
- speechwire_mcp-0.1.0/src/speechwire_mcp/login/parsers.py +189 -0
- speechwire_mcp-0.1.0/src/speechwire_mcp/parsing_helpers.py +75 -0
- speechwire_mcp-0.1.0/src/speechwire_mcp/results/__init__.py +3 -0
- speechwire_mcp-0.1.0/src/speechwire_mcp/results/client.py +48 -0
- speechwire_mcp-0.1.0/src/speechwire_mcp/results/parsers.py +310 -0
- speechwire_mcp-0.1.0/src/speechwire_mcp/rooms/__init__.py +11 -0
- speechwire_mcp-0.1.0/src/speechwire_mcp/rooms/client.py +83 -0
- speechwire_mcp-0.1.0/src/speechwire_mcp/rooms/parsers.py +372 -0
- speechwire_mcp-0.1.0/src/speechwire_mcp/schematics/__init__.py +6 -0
- speechwire_mcp-0.1.0/src/speechwire_mcp/schematics/client.py +49 -0
- speechwire_mcp-0.1.0/src/speechwire_mcp/schematics/parsers.py +243 -0
- speechwire_mcp-0.1.0/src/speechwire_mcp/server.py +802 -0
- speechwire_mcp-0.1.0/src/speechwire_mcp/structure/__init__.py +9 -0
- speechwire_mcp-0.1.0/src/speechwire_mcp/structure/client.py +61 -0
- speechwire_mcp-0.1.0/src/speechwire_mcp/structure/parsers.py +249 -0
- speechwire_mcp-0.1.0/src/speechwire_mcp/teams/__init__.py +7 -0
- speechwire_mcp-0.1.0/src/speechwire_mcp/teams/client.py +87 -0
- speechwire_mcp-0.1.0/src/speechwire_mcp/teams/parsers.py +395 -0
- speechwire_mcp-0.1.0/tests/conftest.py +4 -0
- speechwire_mcp-0.1.0/tests/fake_data.py +124 -0
- speechwire_mcp-0.1.0/tests/test_add_judge.py +127 -0
- speechwire_mcp-0.1.0/tests/test_client_state.py +335 -0
- speechwire_mcp-0.1.0/tests/test_login_parsers.py +782 -0
- speechwire_mcp-0.1.0/tests/test_parsers.py +927 -0
- speechwire_mcp-0.1.0/tests/test_post.py +161 -0
- speechwire_mcp-0.1.0/tests/test_results_parsers.py +402 -0
- speechwire_mcp-0.1.0/tests/test_rooms_parsers.py +521 -0
- speechwire_mcp-0.1.0/tests/test_schematics_parsers.py +354 -0
- speechwire_mcp-0.1.0/tests/test_session_expiry.py +389 -0
- speechwire_mcp-0.1.0/tests/test_structure_parsers.py +544 -0
- speechwire_mcp-0.1.0/tests/test_teams_parsers.py +623 -0
- speechwire_mcp-0.1.0/tests/test_update_judge.py +408 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# Copilot Instructions for SpeechWireMCP
|
|
2
|
+
|
|
3
|
+
## Project Overview
|
|
4
|
+
|
|
5
|
+
SpeechWireMCP is a Model Context Protocol (MCP) server that gives AI assistants
|
|
6
|
+
secure access to SpeechWire tournament judge data for speech-and-debate
|
|
7
|
+
(forensics) competitions. It scrapes manage.speechwire.com behind an
|
|
8
|
+
authenticated session and exposes structured data through MCP tools.
|
|
9
|
+
|
|
10
|
+
## Tech Stack
|
|
11
|
+
|
|
12
|
+
- **Python 3.11+** — use modern syntax (`X | Y` unions, `list[dict]`, etc.)
|
|
13
|
+
- **MCP SDK** (`mcp` package, `FastMCP`) — tool registration via `@mcp.tool()`
|
|
14
|
+
- **requests** — HTTP client with a stateful `requests.Session` for auth cookies
|
|
15
|
+
- **BeautifulSoup4** — HTML parsing of SpeechWire pages
|
|
16
|
+
- **Hatchling** — PEP 517 build backend
|
|
17
|
+
- **pytest** — testing
|
|
18
|
+
- **ruff** — linting (line-length 100, target py311)
|
|
19
|
+
|
|
20
|
+
## Architecture
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
src/speechwire_mcp/
|
|
24
|
+
├── server.py # FastMCP server, tool definitions, lazy client init
|
|
25
|
+
├── client.py # SpeechWireClient (4-step auth), _fetch_and_parse helper
|
|
26
|
+
├── parsing_helpers.py # Shared BS4 utilities (make_soup, td_safe, extract_int_query_param)
|
|
27
|
+
├── judges/
|
|
28
|
+
│ ├── client.py # Judge data retrieval (list, contact, availability, school)
|
|
29
|
+
│ └── parsers.py # Judge HTML → structured data parsing
|
|
30
|
+
├── login/
|
|
31
|
+
│ ├── client.py # Account & tournament discovery after login
|
|
32
|
+
│ └── parsers.py # Account list & tournament list parsing
|
|
33
|
+
├── rooms/
|
|
34
|
+
│ ├── client.py # Room list, usage grid, count retrieval
|
|
35
|
+
│ └── parsers.py # Room HTML → structured data parsing
|
|
36
|
+
├── results/
|
|
37
|
+
│ ├── client.py # Tab sheet results retrieval
|
|
38
|
+
│ └── parsers.py # Results HTML → structured data parsing
|
|
39
|
+
├── schematics/
|
|
40
|
+
│ ├── client.py # Schematic event list & round schematic retrieval
|
|
41
|
+
│ └── parsers.py # Schematic HTML → structured data parsing
|
|
42
|
+
├── structure/
|
|
43
|
+
│ ├── client.py # Timeslot & grouping retrieval
|
|
44
|
+
│ └── parsers.py # Schedule/grouping HTML → structured data parsing
|
|
45
|
+
└── teams/
|
|
46
|
+
├── client.py # Team list, entries, hybrid entries retrieval
|
|
47
|
+
└── parsers.py # Team HTML → structured data parsing
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
- **server.py** is the MCP entry point. Tools are thin wrappers that delegate to
|
|
51
|
+
domain modules (`judges/`, `login/`, `rooms/`, `results/`, `schematics/`,
|
|
52
|
+
`structure/`, `teams/`).
|
|
53
|
+
- **client.py** owns all HTTP and authentication logic. The client automatically
|
|
54
|
+
re-authenticates when it detects a session expiry.
|
|
55
|
+
- **parsing_helpers.py** provides shared BeautifulSoup utilities used by all
|
|
56
|
+
domain parsers.
|
|
57
|
+
- Each **domain module** follows the same pattern: `client.py` calls
|
|
58
|
+
`_fetch_and_parse` with a URL and parser; `parsers.py` contains pure functions
|
|
59
|
+
that take HTML strings and return dicts/lists — keep them side-effect free for
|
|
60
|
+
easy testing.
|
|
61
|
+
- **`_fetch_and_parse`** is the shared pattern: fetch a page, run a parser,
|
|
62
|
+
return a safe default on any failure. Accepts an optional `params` dict for
|
|
63
|
+
query parameters — prefer `params={"key": "val"}` over f-string URL
|
|
64
|
+
interpolation.
|
|
65
|
+
|
|
66
|
+
## Conventions
|
|
67
|
+
|
|
68
|
+
- **Error handling:** never raise from MCP tools. Log errors and return sensible
|
|
69
|
+
defaults (empty list, `None`, etc.) so the AI client always gets a valid
|
|
70
|
+
response.
|
|
71
|
+
- **Logging:** use `logging.getLogger(__name__)` in every module.
|
|
72
|
+
- **No real PII in code or tests:** never use real names, emails, phone
|
|
73
|
+
numbers, or other personally identifiable information anywhere in the
|
|
74
|
+
repository. All test data must use the fictional West Wing characters and
|
|
75
|
+
schools defined in `tests/fake_data.py`. Import constants from that module
|
|
76
|
+
rather than inventing new names inline. Use the `email_for()` helper for
|
|
77
|
+
fake email addresses (all `@example.com`).
|
|
78
|
+
- **Type hints:** annotate all public functions. Use built-in generics
|
|
79
|
+
(`list`, `dict`, `str | None`) — no `typing.List`/`typing.Optional`.
|
|
80
|
+
- **Docstrings:** use NumPy-style docstrings (`Parameters`, `Returns` sections).
|
|
81
|
+
- **Line length:** 100 characters max (enforced by ruff).
|
|
82
|
+
- **URL construction:** use `params={"key": "val"}` in `_fetch_and_parse`
|
|
83
|
+
calls rather than f-string interpolation to prevent injection risks.
|
|
84
|
+
- **Tests:** parser functions get unit tests in `tests/` with sample HTML
|
|
85
|
+
fixtures. Use `pytest`.
|
|
86
|
+
|
|
87
|
+
## Environment Variables
|
|
88
|
+
|
|
89
|
+
The server requires these at runtime (never hard-code credentials):
|
|
90
|
+
|
|
91
|
+
| Variable | Purpose |
|
|
92
|
+
|----------|---------|
|
|
93
|
+
| `SPEECHWIRE_EMAIL` | Account email |
|
|
94
|
+
| `SPEECHWIRE_PASSWORD` | Account password |
|
|
95
|
+
| `SPEECHWIRE_ACCOUNT_ID` | Numeric account ID |
|
|
96
|
+
| `SPEECHWIRE_CIRCUIT_ID` | Numeric circuit ID |
|
|
97
|
+
| `SPEECHWIRE_TOURNAMENT_ID` | Numeric tournament ID |
|
|
98
|
+
| `SPEECHWIRE_MCP_TRANSPORT` | `stdio` (default) or `sse` |
|
|
99
|
+
| `SPEECHWIRE_MCP_HOST` | SSE bind host (default `127.0.0.1`) |
|
|
100
|
+
| `SPEECHWIRE_MCP_PORT` | SSE bind port (default `8080`) |
|
|
101
|
+
|
|
102
|
+
## Development Workflow
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
pip install -e ".[dev]" # editable install with dev deps
|
|
106
|
+
ruff check src/ tests/ # lint
|
|
107
|
+
pytest # test
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
CI runs on Python 3.11, 3.12, and 3.13. Publishing to PyPI is triggered by
|
|
111
|
+
pushing a `v*` tag.
|
|
112
|
+
|
|
113
|
+
## Adding a New MCP Tool
|
|
114
|
+
|
|
115
|
+
1. Add a parser in `<domain>/parsers.py` (pure function, HTML → data).
|
|
116
|
+
2. Add a retrieval function in `<domain>/client.py` using `_fetch_and_parse`.
|
|
117
|
+
3. Export it from `<domain>/__init__.py`.
|
|
118
|
+
4. Register the tool in `server.py` with `@mcp.tool()` and a clear docstring.
|
|
119
|
+
5. Write parser tests in `tests/`.
|
|
120
|
+
|
|
121
|
+
## Process
|
|
122
|
+
|
|
123
|
+
- **Never make git commits or push branches without explicit permission.**
|
|
124
|
+
- **Do not add new dependencies** (packages, libraries, tools) without asking
|
|
125
|
+
first.
|
|
126
|
+
- **Run `ruff check src/ tests/` and `pytest`** before declaring work complete.
|
|
127
|
+
- **Do not modify files outside `src/` and `tests/`** without asking first.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
test:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
strategy:
|
|
13
|
+
matrix:
|
|
14
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v4
|
|
17
|
+
- uses: actions/setup-python@v5
|
|
18
|
+
with:
|
|
19
|
+
python-version: ${{ matrix.python-version }}
|
|
20
|
+
- run: pip install -e ".[dev]"
|
|
21
|
+
- run: ruff check src/ tests/
|
|
22
|
+
- run: pytest
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
strategy:
|
|
12
|
+
matrix:
|
|
13
|
+
python-version: ["3.11", "3.12", "3.13"]
|
|
14
|
+
steps:
|
|
15
|
+
- uses: actions/checkout@v4
|
|
16
|
+
- uses: actions/setup-python@v5
|
|
17
|
+
with:
|
|
18
|
+
python-version: ${{ matrix.python-version }}
|
|
19
|
+
- run: pip install -e ".[dev]"
|
|
20
|
+
- run: ruff check src/ tests/
|
|
21
|
+
- run: pytest
|
|
22
|
+
|
|
23
|
+
build:
|
|
24
|
+
needs: test
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
steps:
|
|
27
|
+
- uses: actions/checkout@v4
|
|
28
|
+
- uses: actions/setup-python@v5
|
|
29
|
+
with:
|
|
30
|
+
python-version: "3.12"
|
|
31
|
+
- run: pip install build
|
|
32
|
+
- run: python -m build
|
|
33
|
+
- uses: actions/upload-artifact@v4
|
|
34
|
+
with:
|
|
35
|
+
name: dist
|
|
36
|
+
path: dist/
|
|
37
|
+
|
|
38
|
+
publish-testpypi:
|
|
39
|
+
needs: build
|
|
40
|
+
runs-on: ubuntu-latest
|
|
41
|
+
environment: testpypi
|
|
42
|
+
permissions:
|
|
43
|
+
id-token: write
|
|
44
|
+
steps:
|
|
45
|
+
- uses: actions/checkout@v4
|
|
46
|
+
with:
|
|
47
|
+
fetch-depth: 0
|
|
48
|
+
- name: Check if tag is on dev
|
|
49
|
+
id: check
|
|
50
|
+
run: |
|
|
51
|
+
if git branch -r --contains "${{ github.ref_name }}" | grep -q 'origin/dev'; then
|
|
52
|
+
echo "on_dev=true" >> "$GITHUB_OUTPUT"
|
|
53
|
+
fi
|
|
54
|
+
- uses: actions/download-artifact@v4
|
|
55
|
+
if: steps.check.outputs.on_dev == 'true'
|
|
56
|
+
with:
|
|
57
|
+
name: dist
|
|
58
|
+
path: dist/
|
|
59
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
60
|
+
if: steps.check.outputs.on_dev == 'true'
|
|
61
|
+
with:
|
|
62
|
+
repository-url: https://test.pypi.org/legacy/
|
|
63
|
+
|
|
64
|
+
publish-pypi:
|
|
65
|
+
needs: build
|
|
66
|
+
runs-on: ubuntu-latest
|
|
67
|
+
environment: pypi
|
|
68
|
+
permissions:
|
|
69
|
+
id-token: write
|
|
70
|
+
steps:
|
|
71
|
+
- uses: actions/checkout@v4
|
|
72
|
+
with:
|
|
73
|
+
fetch-depth: 0
|
|
74
|
+
- name: Check if tag is on main
|
|
75
|
+
id: check
|
|
76
|
+
run: |
|
|
77
|
+
if git branch -r --contains "${{ github.ref_name }}" | grep -q 'origin/main'; then
|
|
78
|
+
echo "on_main=true" >> "$GITHUB_OUTPUT"
|
|
79
|
+
fi
|
|
80
|
+
- uses: actions/download-artifact@v4
|
|
81
|
+
if: steps.check.outputs.on_main == 'true'
|
|
82
|
+
with:
|
|
83
|
+
name: dist
|
|
84
|
+
path: dist/
|
|
85
|
+
- uses: pypa/gh-action-pypi-publish@release/v1
|
|
86
|
+
if: steps.check.outputs.on_main == 'true'
|
|
87
|
+
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# OS files
|
|
2
|
+
.DS_Store
|
|
3
|
+
|
|
4
|
+
# Byte-compiled / optimized / DLL files
|
|
5
|
+
__pycache__/
|
|
6
|
+
*.py[cod]
|
|
7
|
+
*$py.class
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
dist/
|
|
11
|
+
build/
|
|
12
|
+
*.egg-info/
|
|
13
|
+
*.egg
|
|
14
|
+
|
|
15
|
+
# Virtual environments
|
|
16
|
+
.venv/
|
|
17
|
+
venv/
|
|
18
|
+
|
|
19
|
+
# IDE
|
|
20
|
+
.vscode/
|
|
21
|
+
.idea/
|
|
22
|
+
|
|
23
|
+
# Environment files
|
|
24
|
+
.env
|
|
25
|
+
.env.local
|
|
26
|
+
|
|
27
|
+
# pytest / ruff cache
|
|
28
|
+
.pytest_cache/
|
|
29
|
+
.ruff_cache/
|
|
30
|
+
|
|
31
|
+
# Notebooks (may contain credentials)
|
|
32
|
+
notebooks/
|
|
33
|
+
*.ipynb
|
|
34
|
+
|
|
35
|
+
# Copilot
|
|
36
|
+
.copilot/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jessica Moore
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: speechwire-mcp
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Model Context Protocol (MCP) server for interacting with SpeechWire tournament management
|
|
5
|
+
Project-URL: Homepage, https://github.com/jessica-writes-code/speechwire-mcp
|
|
6
|
+
Project-URL: Repository, https://github.com/jessica-writes-code/speechwire-mcp
|
|
7
|
+
Project-URL: Issues, https://github.com/jessica-writes-code/speechwire-mcp/issues
|
|
8
|
+
Author: Jessica Moore
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE
|
|
11
|
+
Keywords: forensics,mcp,model-context-protocol,speech-and-debate,speechwire
|
|
12
|
+
Classifier: Development Status :: 3 - Alpha
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries
|
|
21
|
+
Requires-Python: >=3.11
|
|
22
|
+
Requires-Dist: beautifulsoup4<5.0,>=4.12.0
|
|
23
|
+
Requires-Dist: mcp<2.0,>=1.0.0
|
|
24
|
+
Requires-Dist: requests<3.0,>=2.32.0
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
27
|
+
Requires-Dist: ruff>=0.4.0; extra == 'dev'
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+
# SpeechWire MCP Server
|
|
31
|
+
|
|
32
|
+
[](LICENSE) [](#) [](#)
|
|
33
|
+
|
|
34
|
+
A [Model Context Protocol](https://modelcontextprotocol.io/) (MCP) server that provides AI assistants with secure, authenticated access to [SpeechWire](https://www.speechwire.com/) tournament data for speech-and-debate (forensics) competitions.
|
|
35
|
+
|
|
36
|
+
The server scrapes manage.speechwire.com behind an authenticated session and exposes structured tournament data through MCP tools, enabling AI assistants to help tournament directors manage judge assignments, rooms, teams, entries, and round pairings.
|
|
37
|
+
|
|
38
|
+
## Features
|
|
39
|
+
|
|
40
|
+
- **Judge management** — list judges, contact info, availability, school associations, judge types, and add new judges
|
|
41
|
+
- **Team & entry data** — team rosters, entries by team, hybrid/cross-school entries
|
|
42
|
+
- **Room management** — room lists, usage grids, room-vs-section counts
|
|
43
|
+
- **Schematics** — event lists, round-by-round pairings with judges, rooms, and competitors
|
|
44
|
+
- **Tournament structure** — timeslots, competition groupings
|
|
45
|
+
- **Results** — tab sheets with round outcomes, speaker scores, and placements
|
|
46
|
+
- **Account discovery** — list and select accounts and tournaments interactively
|
|
47
|
+
- **Session management** — automatic re-authentication on session expiry
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install speechwire-mcp
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Set your SpeechWire credentials as environment variables:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
export SPEECHWIRE_EMAIL="your-email@example.com"
|
|
59
|
+
export SPEECHWIRE_PASSWORD="your-password"
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Available MCP Tools
|
|
63
|
+
|
|
64
|
+
| Tool | Description |
|
|
65
|
+
|------|-------------|
|
|
66
|
+
| `speechwire_list_user_accounts` | List accounts available after login |
|
|
67
|
+
| `speechwire_select_user_account` | Select an account to work with |
|
|
68
|
+
| `speechwire_list_user_tournaments` | List tournaments for the selected account |
|
|
69
|
+
| `speechwire_select_user_tournament` | Select a tournament to activate |
|
|
70
|
+
| `speechwire_list_judges` | List all judges with roster details |
|
|
71
|
+
| `speechwire_get_judge_contact` | Get judge email and phone |
|
|
72
|
+
| `speechwire_get_judge_availability` | Get judge availability by timeslot |
|
|
73
|
+
| `speechwire_get_judge_school` | Get judge's school association |
|
|
74
|
+
| `speechwire_add_judge` | Add a new judge to the tournament |
|
|
75
|
+
| `speechwire_update_judge_email` | Update a judge's email address |
|
|
76
|
+
| `speechwire_update_judge_availability` | Update a judge's availability slots |
|
|
77
|
+
| `speechwire_update_judge_school` | Update a judge's school/team affiliation |
|
|
78
|
+
| `speechwire_list_judge_types` | List configured judge types |
|
|
79
|
+
| `speechwire_list_rooms` | List tournament rooms |
|
|
80
|
+
| `speechwire_get_room_usage` | Get room time-slot usage grid |
|
|
81
|
+
| `speechwire_get_room_counts` | Get rooms vs. sections per grouping/round |
|
|
82
|
+
| `speechwire_list_teams` | List registered teams |
|
|
83
|
+
| `speechwire_get_team_entries` | Get entries for a specific team |
|
|
84
|
+
| `speechwire_list_hybrid_entries` | List cross-school hybrid entries |
|
|
85
|
+
| `speechwire_list_timeslots` | List tournament schedule timeslots |
|
|
86
|
+
| `speechwire_list_groupings` | List competition groupings |
|
|
87
|
+
| `speechwire_list_schematic_events` | List schematic events with available rounds |
|
|
88
|
+
| `speechwire_get_round_schematic` | Get pairings for a specific event round |
|
|
89
|
+
| `speechwire_get_tab_sheet` | Get results tab sheet for a grouping |
|
|
90
|
+
|
|
91
|
+
## License
|
|
92
|
+
|
|
93
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# SpeechWire MCP Server
|
|
2
|
+
|
|
3
|
+
[](LICENSE) [](#) [](#)
|
|
4
|
+
|
|
5
|
+
A [Model Context Protocol](https://modelcontextprotocol.io/) (MCP) server that provides AI assistants with secure, authenticated access to [SpeechWire](https://www.speechwire.com/) tournament data for speech-and-debate (forensics) competitions.
|
|
6
|
+
|
|
7
|
+
The server scrapes manage.speechwire.com behind an authenticated session and exposes structured tournament data through MCP tools, enabling AI assistants to help tournament directors manage judge assignments, rooms, teams, entries, and round pairings.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **Judge management** — list judges, contact info, availability, school associations, judge types, and add new judges
|
|
12
|
+
- **Team & entry data** — team rosters, entries by team, hybrid/cross-school entries
|
|
13
|
+
- **Room management** — room lists, usage grids, room-vs-section counts
|
|
14
|
+
- **Schematics** — event lists, round-by-round pairings with judges, rooms, and competitors
|
|
15
|
+
- **Tournament structure** — timeslots, competition groupings
|
|
16
|
+
- **Results** — tab sheets with round outcomes, speaker scores, and placements
|
|
17
|
+
- **Account discovery** — list and select accounts and tournaments interactively
|
|
18
|
+
- **Session management** — automatic re-authentication on session expiry
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install speechwire-mcp
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Set your SpeechWire credentials as environment variables:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
export SPEECHWIRE_EMAIL="your-email@example.com"
|
|
30
|
+
export SPEECHWIRE_PASSWORD="your-password"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Available MCP Tools
|
|
34
|
+
|
|
35
|
+
| Tool | Description |
|
|
36
|
+
|------|-------------|
|
|
37
|
+
| `speechwire_list_user_accounts` | List accounts available after login |
|
|
38
|
+
| `speechwire_select_user_account` | Select an account to work with |
|
|
39
|
+
| `speechwire_list_user_tournaments` | List tournaments for the selected account |
|
|
40
|
+
| `speechwire_select_user_tournament` | Select a tournament to activate |
|
|
41
|
+
| `speechwire_list_judges` | List all judges with roster details |
|
|
42
|
+
| `speechwire_get_judge_contact` | Get judge email and phone |
|
|
43
|
+
| `speechwire_get_judge_availability` | Get judge availability by timeslot |
|
|
44
|
+
| `speechwire_get_judge_school` | Get judge's school association |
|
|
45
|
+
| `speechwire_add_judge` | Add a new judge to the tournament |
|
|
46
|
+
| `speechwire_update_judge_email` | Update a judge's email address |
|
|
47
|
+
| `speechwire_update_judge_availability` | Update a judge's availability slots |
|
|
48
|
+
| `speechwire_update_judge_school` | Update a judge's school/team affiliation |
|
|
49
|
+
| `speechwire_list_judge_types` | List configured judge types |
|
|
50
|
+
| `speechwire_list_rooms` | List tournament rooms |
|
|
51
|
+
| `speechwire_get_room_usage` | Get room time-slot usage grid |
|
|
52
|
+
| `speechwire_get_room_counts` | Get rooms vs. sections per grouping/round |
|
|
53
|
+
| `speechwire_list_teams` | List registered teams |
|
|
54
|
+
| `speechwire_get_team_entries` | Get entries for a specific team |
|
|
55
|
+
| `speechwire_list_hybrid_entries` | List cross-school hybrid entries |
|
|
56
|
+
| `speechwire_list_timeslots` | List tournament schedule timeslots |
|
|
57
|
+
| `speechwire_list_groupings` | List competition groupings |
|
|
58
|
+
| `speechwire_list_schematic_events` | List schematic events with available rounds |
|
|
59
|
+
| `speechwire_get_round_schematic` | Get pairings for a specific event round |
|
|
60
|
+
| `speechwire_get_tab_sheet` | Get results tab sheet for a grouping |
|
|
61
|
+
|
|
62
|
+
## License
|
|
63
|
+
|
|
64
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "speechwire-mcp"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Model Context Protocol (MCP) server for interacting with SpeechWire tournament management"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
license = "MIT"
|
|
11
|
+
requires-python = ">=3.11"
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Jessica Moore" },
|
|
14
|
+
]
|
|
15
|
+
keywords = ["speechwire", "mcp", "model-context-protocol", "speech-and-debate", "forensics"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 3 - Alpha",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.11",
|
|
22
|
+
"Programming Language :: Python :: 3.12",
|
|
23
|
+
"Programming Language :: Python :: 3.13",
|
|
24
|
+
"Programming Language :: Python :: 3.14",
|
|
25
|
+
"Topic :: Software Development :: Libraries",
|
|
26
|
+
]
|
|
27
|
+
dependencies = [
|
|
28
|
+
"mcp>=1.0.0,<2.0",
|
|
29
|
+
"requests>=2.32.0,<3.0",
|
|
30
|
+
"beautifulsoup4>=4.12.0,<5.0",
|
|
31
|
+
]
|
|
32
|
+
|
|
33
|
+
[project.optional-dependencies]
|
|
34
|
+
dev = [
|
|
35
|
+
"pytest>=8.0",
|
|
36
|
+
"ruff>=0.4.0",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
[project.scripts]
|
|
40
|
+
speechwire-mcp = "speechwire_mcp.server:main"
|
|
41
|
+
|
|
42
|
+
[project.urls]
|
|
43
|
+
Homepage = "https://github.com/jessica-writes-code/speechwire-mcp"
|
|
44
|
+
Repository = "https://github.com/jessica-writes-code/speechwire-mcp"
|
|
45
|
+
Issues = "https://github.com/jessica-writes-code/speechwire-mcp/issues"
|
|
46
|
+
|
|
47
|
+
[tool.hatch.build.targets.wheel]
|
|
48
|
+
packages = ["src/speechwire_mcp"]
|
|
49
|
+
|
|
50
|
+
[tool.pytest.ini_options]
|
|
51
|
+
testpaths = ["tests"]
|
|
52
|
+
|
|
53
|
+
[tool.ruff]
|
|
54
|
+
target-version = "py311"
|
|
55
|
+
line-length = 100
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"""speechwire-mcp: Model Context Protocol server for SpeechWire tournament management."""
|
|
2
|
+
|
|
3
|
+
from speechwire_mcp.client import SpeechWireClient, SpeechWireAuthError
|
|
4
|
+
from speechwire_mcp.judges import (
|
|
5
|
+
get_judge_list,
|
|
6
|
+
get_judge_contact,
|
|
7
|
+
get_judge_availability,
|
|
8
|
+
get_judge_school,
|
|
9
|
+
)
|
|
10
|
+
from speechwire_mcp.login import get_accounts, get_tournaments
|
|
11
|
+
from speechwire_mcp.rooms import get_room_counts, get_room_list, get_room_usage
|
|
12
|
+
from speechwire_mcp.schematics import get_schematic_events, get_round_schematic
|
|
13
|
+
from speechwire_mcp.structure import get_groupings, get_timeslots
|
|
14
|
+
from speechwire_mcp.teams import get_team_list, get_team_entries, get_hybrid_entries
|
|
15
|
+
from speechwire_mcp.results import get_tab_sheet
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"SpeechWireClient",
|
|
19
|
+
"SpeechWireAuthError",
|
|
20
|
+
"get_judge_list",
|
|
21
|
+
"get_judge_contact",
|
|
22
|
+
"get_judge_availability",
|
|
23
|
+
"get_judge_school",
|
|
24
|
+
"get_accounts",
|
|
25
|
+
"get_tournaments",
|
|
26
|
+
"get_room_counts",
|
|
27
|
+
"get_room_list",
|
|
28
|
+
"get_room_usage",
|
|
29
|
+
"get_schematic_events",
|
|
30
|
+
"get_round_schematic",
|
|
31
|
+
"get_groupings",
|
|
32
|
+
"get_timeslots",
|
|
33
|
+
"get_team_list",
|
|
34
|
+
"get_team_entries",
|
|
35
|
+
"get_hybrid_entries",
|
|
36
|
+
"get_tab_sheet",
|
|
37
|
+
]
|