mcp-server-microsoft-tasks 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.
Files changed (93) hide show
  1. mcp_server_microsoft_tasks-0.1.0/.github/CODEOWNERS +6 -0
  2. mcp_server_microsoft_tasks-0.1.0/.github/ISSUE_TEMPLATE/bug_report.md +42 -0
  3. mcp_server_microsoft_tasks-0.1.0/.github/ISSUE_TEMPLATE/feature_request.md +29 -0
  4. mcp_server_microsoft_tasks-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +26 -0
  5. mcp_server_microsoft_tasks-0.1.0/.github/copilot-instructions.md +6 -0
  6. mcp_server_microsoft_tasks-0.1.0/.github/dependabot.yml +7 -0
  7. mcp_server_microsoft_tasks-0.1.0/.github/gh-scripts/assign-repo-to-team.sh +70 -0
  8. mcp_server_microsoft_tasks-0.1.0/.github/gh-scripts/setup-branch-protection.sh +173 -0
  9. mcp_server_microsoft_tasks-0.1.0/.github/workflows/HARNESS_JOB.md +54 -0
  10. mcp_server_microsoft_tasks-0.1.0/.github/workflows/ci.yml +119 -0
  11. mcp_server_microsoft_tasks-0.1.0/.github/workflows/release.yml +51 -0
  12. mcp_server_microsoft_tasks-0.1.0/.gitignore +31 -0
  13. mcp_server_microsoft_tasks-0.1.0/.markdownlint.yaml +18 -0
  14. mcp_server_microsoft_tasks-0.1.0/AGENTS.md +178 -0
  15. mcp_server_microsoft_tasks-0.1.0/CHANGELOG.md +58 -0
  16. mcp_server_microsoft_tasks-0.1.0/CLAUDE.md +6 -0
  17. mcp_server_microsoft_tasks-0.1.0/CODE_OF_CONDUCT.md +43 -0
  18. mcp_server_microsoft_tasks-0.1.0/CONTRIBUTING.md +224 -0
  19. mcp_server_microsoft_tasks-0.1.0/ENGINEERING_PRINCIPLES.md +454 -0
  20. mcp_server_microsoft_tasks-0.1.0/LICENSE +21 -0
  21. mcp_server_microsoft_tasks-0.1.0/LICENSE-APACHE +184 -0
  22. mcp_server_microsoft_tasks-0.1.0/LICENSE-MIT +21 -0
  23. mcp_server_microsoft_tasks-0.1.0/PKG-INFO +246 -0
  24. mcp_server_microsoft_tasks-0.1.0/README.md +207 -0
  25. mcp_server_microsoft_tasks-0.1.0/SECURITY.md +39 -0
  26. mcp_server_microsoft_tasks-0.1.0/docs/app-concept.md +250 -0
  27. mcp_server_microsoft_tasks-0.1.0/docs/howto-oss.md +880 -0
  28. mcp_server_microsoft_tasks-0.1.0/docs/markdown-style.md +92 -0
  29. mcp_server_microsoft_tasks-0.1.0/docs/proposals/README.md +53 -0
  30. mcp_server_microsoft_tasks-0.1.0/docs/proposals/_template.md +47 -0
  31. mcp_server_microsoft_tasks-0.1.0/docs/testconcept.md +369 -0
  32. mcp_server_microsoft_tasks-0.1.0/pyproject.toml +135 -0
  33. mcp_server_microsoft_tasks-0.1.0/repo.ini +112 -0
  34. mcp_server_microsoft_tasks-0.1.0/scripts/README.md +36 -0
  35. mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/__init__.py +14 -0
  36. mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/auth/__init__.py +248 -0
  37. mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/auth/flow.py +204 -0
  38. mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/auth/store.py +133 -0
  39. mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/auth/tokens.py +19 -0
  40. mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/cli.py +99 -0
  41. mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/login_state.py +60 -0
  42. mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/server.py +458 -0
  43. mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/__init__.py +16 -0
  44. mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/_common.py +35 -0
  45. mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/_shape.py +173 -0
  46. mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/login_begin.py +220 -0
  47. mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/login_status.py +145 -0
  48. mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/planner_buckets.py +64 -0
  49. mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/planner_plan_get.py +58 -0
  50. mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/planner_plans.py +145 -0
  51. mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/planner_task_get.py +119 -0
  52. mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/planner_tasks.py +95 -0
  53. mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/tasks_assigned_to_me.py +170 -0
  54. mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/tasks_search.py +167 -0
  55. mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/todo_list_get.py +61 -0
  56. mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/todo_lists.py +76 -0
  57. mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/todo_task_get.py +63 -0
  58. mcp_server_microsoft_tasks-0.1.0/src/microsoft_tasks_mcp/tools/todo_tasks.py +88 -0
  59. mcp_server_microsoft_tasks-0.1.0/tests/conftest.py +36 -0
  60. mcp_server_microsoft_tasks-0.1.0/tests/harness/test_auth_smoke.py +82 -0
  61. mcp_server_microsoft_tasks-0.1.0/tests/harness/test_cross_source.py +63 -0
  62. mcp_server_microsoft_tasks-0.1.0/tests/harness/test_login_status.py +40 -0
  63. mcp_server_microsoft_tasks-0.1.0/tests/harness/test_planner_read.py +126 -0
  64. mcp_server_microsoft_tasks-0.1.0/tests/harness/test_todo_read.py +96 -0
  65. mcp_server_microsoft_tasks-0.1.0/tests/integration/__init__.py +0 -0
  66. mcp_server_microsoft_tasks-0.1.0/tests/integration/test_cross_source_tools.py +66 -0
  67. mcp_server_microsoft_tasks-0.1.0/tests/integration/test_planner_read_tools.py +151 -0
  68. mcp_server_microsoft_tasks-0.1.0/tests/integration/test_todo_read_tools.py +144 -0
  69. mcp_server_microsoft_tasks-0.1.0/tests/run_tests.sh +92 -0
  70. mcp_server_microsoft_tasks-0.1.0/tests/unit/auth/__init__.py +0 -0
  71. mcp_server_microsoft_tasks-0.1.0/tests/unit/auth/test_flow.py +148 -0
  72. mcp_server_microsoft_tasks-0.1.0/tests/unit/auth/test_init.py +203 -0
  73. mcp_server_microsoft_tasks-0.1.0/tests/unit/auth/test_store.py +100 -0
  74. mcp_server_microsoft_tasks-0.1.0/tests/unit/test_cli.py +92 -0
  75. mcp_server_microsoft_tasks-0.1.0/tests/unit/test_login_state.py +185 -0
  76. mcp_server_microsoft_tasks-0.1.0/tests/unit/test_server.py +81 -0
  77. mcp_server_microsoft_tasks-0.1.0/tests/unit/test_smoke.py +15 -0
  78. mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/__init__.py +0 -0
  79. mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/test_common.py +49 -0
  80. mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/test_login_begin.py +450 -0
  81. mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/test_login_status.py +362 -0
  82. mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/test_planner_buckets.py +84 -0
  83. mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/test_planner_plan_get.py +73 -0
  84. mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/test_planner_plans.py +152 -0
  85. mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/test_planner_task_get.py +138 -0
  86. mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/test_planner_tasks.py +166 -0
  87. mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/test_tasks_assigned_to_me.py +228 -0
  88. mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/test_tasks_search.py +157 -0
  89. mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/test_todo_list_get.py +94 -0
  90. mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/test_todo_lists.py +166 -0
  91. mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/test_todo_task_get.py +84 -0
  92. mcp_server_microsoft_tasks-0.1.0/tests/unit/tools/test_todo_tasks.py +195 -0
  93. mcp_server_microsoft_tasks-0.1.0/uv.lock +1307 -0
@@ -0,0 +1,6 @@
1
+ # SPDX-License-Identifier: MIT OR Apache-2.0
2
+ # Default owners for everything
3
+ * @XMV-Solutions-GmbH/open-source
4
+
5
+ # Documentation can have different reviewers
6
+ # /docs/ @XMV-Solutions-GmbH/docs-team
@@ -0,0 +1,42 @@
1
+ ---
2
+ name: Bug Report
3
+ about: Create a report to help us improve
4
+ title: "[BUG] "
5
+ labels: ["bug"]
6
+ assignees: []
7
+ ---
8
+
9
+ <!-- SPDX-License-Identifier: MIT OR Apache-2.0 -->
10
+
11
+ ## 🐛 Bug Description
12
+
13
+ A clear and concise description of what the bug is.
14
+
15
+ ## 🔁 Steps to Reproduce
16
+
17
+ 1. Go to '...'
18
+ 2. Click on '....'
19
+ 3. Scroll down to '....'
20
+ 4. See error
21
+
22
+ ## 🧐 Expected Behaviour
23
+
24
+ A clear and concise description of what you expected to happen.
25
+
26
+ ## 😯 Actual Behaviour
27
+
28
+ A clear and concise description of what actually happened.
29
+
30
+ ## 📸 Screenshots
31
+
32
+ If applicable, add screenshots to help explain your problem.
33
+
34
+ ## 💻 Environment
35
+
36
+ - **OS:** [e.g. Linux, macOS, Windows]
37
+ - **Version:** [e.g. 1.0.0]
38
+ - **Toolchain:** [e.g. Rust 1.82, Node 20]
39
+
40
+ ## 📋 Additional Context
41
+
42
+ Add any other context about the problem here.
@@ -0,0 +1,29 @@
1
+ ---
2
+ name: Feature Request
3
+ about: Suggest an idea for this project
4
+ title: "[FEAT] "
5
+ labels: ["enhancement"]
6
+ assignees: []
7
+ ---
8
+
9
+ <!-- SPDX-License-Identifier: MIT OR Apache-2.0 -->
10
+
11
+ ## ✨ Feature Description
12
+
13
+ A clear and concise description of what the feature is.
14
+
15
+ ## 😫 Problem it Solves
16
+
17
+ Describe the problem your proposal solves. "I'm always frustrated when..."
18
+
19
+ ## 💡 Possible Implementation
20
+
21
+ Describes how you imagine the implementation.
22
+
23
+ ## 🔄 Alternatives Considered
24
+
25
+ A clear and concise description of any alternative solutions or features you've considered.
26
+
27
+ ## 📋 Additional Context
28
+
29
+ Add any other context or screenshots about the feature request here.
@@ -0,0 +1,26 @@
1
+ <!-- SPDX-License-Identifier: MIT OR Apache-2.0 -->
2
+
3
+ ## 📝 Description
4
+
5
+ Please include a summary of the change and which issue is fixed.
6
+
7
+ Fixes # (issue)
8
+
9
+ ## 🧪 Testing
10
+
11
+ Please describe the tests that you ran to verify your changes.
12
+
13
+ - [ ] Unit tests
14
+ - [ ] Integration tests
15
+ - [ ] Manual tests
16
+
17
+ ## ✅ Checklist
18
+
19
+ - [ ] My code follows the code style of this project
20
+ - [ ] I have performed a self-review of my own code
21
+ - [ ] I have commented my code, particularly in hard-to-understand areas
22
+ - [ ] I have made corresponding changes to the documentation
23
+ - [ ] My changes generate no new warnings
24
+ - [ ] I have added tests that prove my fix is effective or that my feature works
25
+ - [ ] New and existing unit tests pass locally with my changes
26
+ - [ ] Any dependent changes have been merged and published in downstream modules
@@ -0,0 +1,6 @@
1
+ <!-- SPDX-License-Identifier: MIT OR Apache-2.0 -->
2
+ # GitHub Copilot instructions
3
+
4
+ This file exists because GitHub Copilot auto-discovers it. The actual brief for any AI agent in this repo — Copilot, Codex, Claude Code, Cursor, Aider, all of them — is **[`AGENTS.md`](../AGENTS.md)** at the repo root. Read that first; it's the same content for every tool.
5
+
6
+ This file is intentionally minimal. If a Copilot-only convention ever becomes load-bearing (e.g. a Copilot-Chat-specific behaviour), capture it below this header — until then, this file is just a pointer so Copilot finds the brief at its conventional location.
@@ -0,0 +1,7 @@
1
+ version: 2
2
+ updates:
3
+ - package-ecosystem: "github-actions"
4
+ directory: "/"
5
+ schedule:
6
+ interval: "weekly"
7
+ open-pull-requests-limit: 10
@@ -0,0 +1,70 @@
1
+ #!/usr/bin/env bash
2
+ # SPDX-License-Identifier: MIT OR Apache-2.0
3
+ #
4
+ # assign-repo-to-team.sh
5
+ #
6
+ # Assigns the repository to a team with write access.
7
+ # Configuration is loaded from repo.ini in the repository root.
8
+ #
9
+ # Usage:
10
+ # ./.github/gh-scripts/assign-repo-to-team.sh
11
+ #
12
+ # Environment variables can override repo.ini values:
13
+ # ORG, REPO, TEAM_SLUG
14
+
15
+ set -euo pipefail
16
+
17
+ # ---------------------------
18
+ # Load configuration
19
+ # ---------------------------
20
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
21
+ REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
22
+ CONFIG_FILE="${REPO_ROOT}/repo.ini"
23
+
24
+ if [[ -f "${CONFIG_FILE}" ]]; then
25
+ echo ">> Loading configuration from repo.ini"
26
+ # shellcheck source=/dev/null
27
+ source "${CONFIG_FILE}"
28
+ else
29
+ echo "WARNING: repo.ini not found, using defaults/environment variables" >&2
30
+ fi
31
+
32
+ # ---------------------------
33
+ # Configuration (override via env)
34
+ # ---------------------------
35
+ ORG="${ORG:-XMV-Solutions-GmbH}"
36
+ REPO="${REPO:-oss-project-template}"
37
+ TEAM_SLUG="${TEAM_SLUG:-open-source}"
38
+
39
+ # ---------------------------
40
+ # Helpers
41
+ # ---------------------------
42
+ require_cmd() {
43
+ command -v "$1" >/dev/null 2>&1 || {
44
+ echo "ERROR: Missing required command: $1" >&2
45
+ exit 1
46
+ }
47
+ }
48
+
49
+ # ---------------------------
50
+ # Preconditions
51
+ # ---------------------------
52
+ require_cmd gh
53
+
54
+ if ! gh auth status >/dev/null 2>&1; then
55
+ echo "ERROR: gh is not authenticated. Run: gh auth login" >&2
56
+ exit 1
57
+ fi
58
+
59
+ # ---------------------------
60
+ # Execute
61
+ # ---------------------------
62
+ FULL_REPO="${ORG}/${REPO}"
63
+
64
+ echo ">> Granting write access to team '${TEAM_SLUG}' on repo '${FULL_REPO}'"
65
+
66
+ gh api -X PUT "orgs/${ORG}/teams/${TEAM_SLUG}/repos/${ORG}/${REPO}" \
67
+ -H "Accept: application/vnd.github+json" \
68
+ -f permission="push"
69
+
70
+ echo ">> Done."
@@ -0,0 +1,173 @@
1
+ #!/usr/bin/env bash
2
+ # SPDX-License-Identifier: MIT OR Apache-2.0
3
+ #
4
+ # setup-branch-protection.sh
5
+ #
6
+ # Sets PR-only branch protection for the default branch (usually main),
7
+ # restricts direct pushes to a maintainer team, and requires CI status checks.
8
+ # Configuration is loaded from repo.ini in the repository root.
9
+ #
10
+ # Usage:
11
+ # ./.github/gh-scripts/setup-branch-protection.sh
12
+ #
13
+ # Environment variables can override repo.ini values:
14
+ # ORG, REPO, BRANCH, TEAM_SLUG, REQUIRED_APPROVALS, etc.
15
+ #
16
+ # IMPORTANT:
17
+ # The required status check contexts MUST match the workflow/job names.
18
+ # Configure STATUS_CHECKS in repo.ini to match your CI workflow job names.
19
+
20
+ set -euo pipefail
21
+
22
+ # ---------------------------
23
+ # Load configuration
24
+ # ---------------------------
25
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
26
+ REPO_ROOT="$(cd "${SCRIPT_DIR}/../.." && pwd)"
27
+ CONFIG_FILE="${REPO_ROOT}/repo.ini"
28
+
29
+ if [[ -f "${CONFIG_FILE}" ]]; then
30
+ echo ">> Loading configuration from repo.ini"
31
+ # shellcheck source=/dev/null
32
+ source "${CONFIG_FILE}"
33
+ else
34
+ echo "WARNING: repo.ini not found, using defaults/environment variables" >&2
35
+ fi
36
+
37
+ # ---------------------------
38
+ # Configuration (override via env)
39
+ # ---------------------------
40
+ ORG="${ORG:-XMV-Solutions-GmbH}"
41
+ REPO="${REPO:-oss-project-template}"
42
+ BRANCH="${BRANCH:-main}"
43
+ TEAM_SLUG="${TEAM_SLUG:-open-source}"
44
+
45
+ # PR review rules
46
+ REQUIRED_APPROVALS="${REQUIRED_APPROVALS:-0}"
47
+ REQUIRE_CODEOWNER_REVIEWS="${REQUIRE_CODEOWNER_REVIEWS:-false}"
48
+ DISMISS_STALE_REVIEWS="${DISMISS_STALE_REVIEWS:-true}"
49
+
50
+ # Admin enforcement
51
+ ENFORCE_ADMINS="${ENFORCE_ADMINS:-true}"
52
+
53
+ # Required status checks (comma-separated string from repo.ini)
54
+ # Format: "check1,check2" - commas separate checks, spaces are preserved within check names
55
+ # Example: "CI / lint,CI / test" results in two checks: "CI / lint" and "CI / test"
56
+ STATUS_CHECKS_STRING="${STATUS_CHECKS:-lint,test}"
57
+
58
+ # Convert comma-separated string to array, preserving spaces within check names
59
+ IFS=',' read -ra STATUS_CHECKS_ARRAY <<< "${STATUS_CHECKS_STRING}"
60
+
61
+ # Optional: allow certain actors to push to main besides team
62
+ EXTRA_USERS="${EXTRA_USERS:-}"
63
+ EXTRA_APPS="${EXTRA_APPS:-}"
64
+
65
+ FULL_REPO="${ORG}/${REPO}"
66
+
67
+ # ---------------------------
68
+ # Helpers
69
+ # ---------------------------
70
+ require_cmd() {
71
+ command -v "$1" >/dev/null 2>&1 || {
72
+ echo "ERROR: Missing required command: $1" >&2
73
+ exit 1
74
+ }
75
+ }
76
+
77
+ split_csv_to_json_array() {
78
+ local csv="${1:-}"
79
+ if [[ -z "${csv}" ]]; then
80
+ echo "[]"
81
+ return
82
+ fi
83
+ local normalized
84
+ normalized="$(echo "${csv}" | sed 's/[[:space:]]//g')"
85
+ echo "${normalized}" | awk -F',' '{
86
+ printf("[");
87
+ for (i=1; i<=NF; i++) {
88
+ printf("\"%s\"", $i);
89
+ if (i<NF) printf(",");
90
+ }
91
+ printf("]");
92
+ }'
93
+ }
94
+
95
+ json_array_from_bash_array() {
96
+ # Print JSON array from STATUS_CHECKS_ARRAY bash array
97
+ printf '%s\n' "${STATUS_CHECKS_ARRAY[@]}" | jq -R . | jq -s .
98
+ }
99
+
100
+ # ---------------------------
101
+ # Preconditions
102
+ # ---------------------------
103
+ require_cmd gh
104
+ require_cmd jq
105
+
106
+ if ! gh auth status >/dev/null 2>&1; then
107
+ echo "ERROR: gh is not authenticated. Run: gh auth login" >&2
108
+ exit 1
109
+ fi
110
+
111
+ echo ">> Repo: ${FULL_REPO}"
112
+ gh repo view "${FULL_REPO}" >/dev/null
113
+
114
+ echo ">> Team: ${ORG}/${TEAM_SLUG}"
115
+ gh api "orgs/${ORG}/teams/${TEAM_SLUG}" >/dev/null
116
+
117
+ USERS_JSON="$(split_csv_to_json_array "${EXTRA_USERS}")"
118
+ APPS_JSON="$(split_csv_to_json_array "${EXTRA_APPS}")"
119
+ CHECKS_JSON="$(json_array_from_bash_array)"
120
+
121
+ echo ">> Required status checks:"
122
+ echo "${CHECKS_JSON}" | jq -r '.[]' | sed 's/^/ - /'
123
+
124
+ # ---------------------------
125
+ # Apply protection
126
+ # ---------------------------
127
+ echo ">> Applying branch protection to ${FULL_REPO}:${BRANCH}"
128
+
129
+ # Build the simplified JSON payload for the PUT request
130
+ # Note: GitHub API strictness requires proper JSON types (booleans as true/false, not strings)
131
+ PAYLOAD=$(jq -n \
132
+ --arg enforce_admins "$ENFORCE_ADMINS" \
133
+ --arg required_approvals "$REQUIRED_APPROVALS" \
134
+ --arg dismiss_stale "$DISMISS_STALE_REVIEWS" \
135
+ --arg code_owner "$REQUIRE_CODEOWNER_REVIEWS" \
136
+ --arg team_slug "$TEAM_SLUG" \
137
+ --argjson checks "$CHECKS_JSON" \
138
+ --argjson extra_users "$USERS_JSON" \
139
+ --argjson extra_apps "$APPS_JSON" \
140
+ '{
141
+ required_status_checks: {
142
+ strict: true,
143
+ contexts: $checks
144
+ },
145
+ enforce_admins: ($enforce_admins == "true"),
146
+ required_pull_request_reviews: {
147
+ dismiss_stale_reviews: ($dismiss_stale == "true"),
148
+ require_code_owner_reviews: ($code_owner == "true"),
149
+ required_approving_review_count: ($required_approvals | tonumber),
150
+ require_last_push_approval: false
151
+ },
152
+ restrictions: {
153
+ users: $extra_users,
154
+ teams: [$team_slug],
155
+ apps: $extra_apps
156
+ },
157
+ required_conversation_resolution: true,
158
+ allow_force_pushes: false,
159
+ allow_deletions: false
160
+ }'
161
+ )
162
+
163
+ echo ">> Config Payload generated"
164
+
165
+ # Send the request
166
+ echo "$PAYLOAD" | gh api -X PUT "repos/${FULL_REPO}/branches/${BRANCH}/protection" \
167
+ -H "Accept: application/vnd.github+json" \
168
+ --input - \
169
+ >/dev/null
170
+
171
+ echo ">> Done."
172
+
173
+ echo ">> NOTE: If checks don't exist yet, GitHub will not be able to enforce them until the workflow runs at least once."
@@ -0,0 +1,54 @@
1
+ <!-- SPDX-License-Identifier: MIT OR Apache-2.0 -->
2
+ # Harness job snippet
3
+
4
+ Drop the YAML below into `ci.yml` once the project has a real external sandbox to test against. The harness layer is the **gate** per [`ENGINEERING_PRINCIPLES.md` § 5](../../ENGINEERING_PRINCIPLES.md): no feature ticket lands before this is green.
5
+
6
+ The snippet is structured to match the rest of `ci.yml`. Two design choices are load-bearing:
7
+
8
+ - **`needs: test`** — run only after lint and test pass, so we don't burn an external-API call when the basics are red.
9
+ - **`if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository`** — skip silently on PRs from forks. Forks don't get repo secrets, so a fork PR running this job would fail with no useful signal. The skip-silently pattern is what the sister projects (sharepoint-mcp, outlook-mcp) settled on so external contributions aren't blocked on something they can't provide.
10
+
11
+ Inside the job: restore the credential from a base64-encoded repo secret, write it where the harness expects, run the harness suite. The "skip when secret is empty" early-exit means a freshly-cloned project with no secret configured still lands in the green path until the maintainer flips the harness on.
12
+
13
+ ```yaml
14
+ harness:
15
+ runs-on: ubuntu-latest
16
+ needs: test
17
+ if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
18
+ steps:
19
+ - uses: actions/checkout@v6
20
+
21
+ # Replace the language-setup steps with the project's stack.
22
+ # Example for Python:
23
+ # - uses: actions/setup-python@v6
24
+ # with:
25
+ # python-version: "3.11"
26
+ # - uses: astral-sh/setup-uv@v7
27
+ # - run: uv sync --extra dev
28
+
29
+ - name: Restore harness credential from repo secret
30
+ env:
31
+ # Project-specific secret name. Sister projects use
32
+ # SHAREPOINT_HARNESS_TOKEN_JSON / OUTLOOK_HARNESS_TOKEN_JSON.
33
+ HARNESS_CRED_B64: ${{ secrets.HARNESS_CRED_B64 }}
34
+ run: |
35
+ if [ -z "$HARNESS_CRED_B64" ]; then
36
+ echo "::warning::HARNESS_CRED_B64 not set — harness tests will be skipped."
37
+ exit 0
38
+ fi
39
+ mkdir -p ~/.cache/<project-name>/harness
40
+ printf '%s' "$HARNESS_CRED_B64" | base64 -d > ~/.cache/<project-name>/harness/cred.json
41
+ chmod 600 ~/.cache/<project-name>/harness/cred.json
42
+ echo "Harness credential restored ($(wc -c < ~/.cache/<project-name>/harness/cred.json) bytes)."
43
+
44
+ - name: Run harness tests against the real external system
45
+ run: ./tests/run_tests.sh harness
46
+ ```
47
+
48
+ ## Required-status-checks update
49
+
50
+ When you flip the harness job on, add `harness` to `STATUS_CHECKS` in `repo.ini` and re-run `.github/gh-scripts/setup-branch-protection.sh` so branch protection actually requires it.
51
+
52
+ ## Token rotation
53
+
54
+ If the credential is a refresh token, it rotates every ~60–90 days for most providers. Add a recurring chore in `CLAUDE.md` and a `scripts/renew-harness-token.sh` (per [`ENGINEERING_PRINCIPLES.md` § 8](../../ENGINEERING_PRINCIPLES.md)) so renewing it is a one-command flow before CI starts failing on its own.
@@ -0,0 +1,119 @@
1
+ # Three-job CI: lint / test / harness. Same shape as the sister
2
+ # Microsoft-Graph MCP projects (sharepoint-mcp, outlook-mcp). The
3
+ # harness job is gated behind a repo secret and skips silently when
4
+ # absent, so PRs from forks don't get blocked.
5
+ #
6
+ # Per ENGINEERING_PRINCIPLES § 6 (CI vigilance): every push is watched
7
+ # to completion; trunk red is a P0 incident.
8
+
9
+ name: CI
10
+
11
+ on:
12
+ push:
13
+ branches: [main]
14
+ pull_request:
15
+ branches: [main]
16
+
17
+ jobs:
18
+ lint:
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@v6
22
+
23
+ - name: Lint Markdown
24
+ uses: DavidAnson/markdownlint-cli2-action@v23
25
+ with:
26
+ globs: |
27
+ **/*.md
28
+
29
+ - name: Set up Python
30
+ uses: actions/setup-python@v6
31
+ with:
32
+ python-version: "3.11"
33
+
34
+ - name: Install uv
35
+ uses: astral-sh/setup-uv@v7
36
+
37
+ - name: Install package + dev dependencies
38
+ run: uv sync --extra dev
39
+
40
+ - name: ruff check
41
+ run: uv run ruff check src tests
42
+
43
+ - name: ruff format check
44
+ run: uv run ruff format --check src tests
45
+
46
+ - name: mypy
47
+ run: uv run mypy src/microsoft_tasks_mcp tests
48
+
49
+ test:
50
+ runs-on: ubuntu-latest
51
+ steps:
52
+ - uses: actions/checkout@v6
53
+
54
+ - name: Compare licences
55
+ run: diff LICENSE LICENSE-MIT
56
+
57
+ - name: Set up Python
58
+ uses: actions/setup-python@v6
59
+ with:
60
+ python-version: "3.11"
61
+
62
+ - name: Install uv
63
+ uses: astral-sh/setup-uv@v7
64
+
65
+ - name: Install package + dev dependencies
66
+ run: uv sync --extra dev
67
+
68
+ - name: Run unit + integration tests with coverage
69
+ run: ./tests/run_tests.sh
70
+
71
+ - name: Upload coverage to Codecov
72
+ if: ${{ hashFiles('coverage.xml') != '' }}
73
+ uses: codecov/codecov-action@v5
74
+ with:
75
+ files: coverage.xml
76
+ fail_ci_if_error: false
77
+ verbose: false
78
+
79
+ harness:
80
+ runs-on: ubuntu-latest
81
+ needs: test
82
+ # Run harness tests against the real Microsoft 365 sandbox using the
83
+ # cached refresh token from the MS_TASKS_HARNESS_TOKEN_JSON secret.
84
+ # Skips silently when the secret isn't available (e.g. on PRs from
85
+ # forks where secrets aren't passed) so external contributions
86
+ # aren't blocked on something they can't provide.
87
+ if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository
88
+ steps:
89
+ - uses: actions/checkout@v6
90
+
91
+ - name: Set up Python
92
+ uses: actions/setup-python@v6
93
+ with:
94
+ python-version: "3.11"
95
+
96
+ - name: Install uv
97
+ uses: astral-sh/setup-uv@v7
98
+
99
+ - name: Install package + dev dependencies
100
+ run: uv sync --extra dev
101
+
102
+ - name: Restore harness token cache from secret
103
+ env:
104
+ TOKEN_B64: ${{ secrets.MS_TASKS_HARNESS_TOKEN_JSON }}
105
+ run: |
106
+ if [ -z "$TOKEN_B64" ]; then
107
+ echo "::warning::MS_TASKS_HARNESS_TOKEN_JSON not set — harness tests will be skipped."
108
+ exit 0
109
+ fi
110
+ mkdir -p ~/.cache/mcp-server-microsoft-tasks/harness
111
+ printf '%s' "$TOKEN_B64" | base64 -d > ~/.cache/mcp-server-microsoft-tasks/harness/token.json
112
+ chmod 600 ~/.cache/mcp-server-microsoft-tasks/harness/token.json
113
+ echo "Harness token cache restored ($(wc -c < ~/.cache/mcp-server-microsoft-tasks/harness/token.json) bytes)."
114
+
115
+ - name: Run harness tests against real Microsoft Graph
116
+ env:
117
+ # Use plain-file backend explicitly (CI runners have no keyring).
118
+ MS_TASKS_TOKEN_STORE: file
119
+ run: ./tests/run_tests.sh harness
@@ -0,0 +1,51 @@
1
+ name: release
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - "v*"
7
+
8
+ permissions:
9
+ contents: write
10
+ id-token: write # for PyPI Trusted Publisher (OIDC)
11
+
12
+ jobs:
13
+ build-and-publish:
14
+ runs-on: ubuntu-latest
15
+ environment:
16
+ name: pypi
17
+ url: https://pypi.org/p/mcp-server-microsoft-tasks
18
+ steps:
19
+ - uses: actions/checkout@v6
20
+
21
+ - name: Set up Python
22
+ uses: actions/setup-python@v6
23
+ with:
24
+ python-version: "3.11"
25
+
26
+ - name: Install uv
27
+ uses: astral-sh/setup-uv@v7
28
+
29
+ - name: Install package + dev dependencies
30
+ run: uv sync --extra dev
31
+
32
+ - name: Run unit + integration tests (gate)
33
+ run: ./tests/run_tests.sh
34
+
35
+ - name: Build wheel + sdist
36
+ run: uv build
37
+
38
+ - name: Publish to PyPI (OIDC Trusted Publisher)
39
+ # Requires PyPI Trusted Publisher configured for this repo +
40
+ # the `pypi` GH environment.
41
+ run: uv publish
42
+
43
+ github-release:
44
+ runs-on: ubuntu-latest
45
+ needs: build-and-publish
46
+ steps:
47
+ - uses: actions/checkout@v6
48
+ - name: Create GitHub Release
49
+ uses: softprops/action-gh-release@v3
50
+ with:
51
+ generate_release_notes: true
@@ -0,0 +1,31 @@
1
+ # Claude Code per-machine settings (bypass permissions etc.)
2
+ .claude/settings.local.json
3
+ .claude/scheduled_tasks.lock
4
+ .claude/scheduled_tasks.json
5
+
6
+ # Python
7
+ __pycache__/
8
+ *.py[cod]
9
+ *.egg-info/
10
+ .venv/
11
+ venv/
12
+ build/
13
+ dist/
14
+
15
+ # Editor / OS
16
+ .vscode/
17
+ .idea/
18
+ *.swp
19
+ .DS_Store
20
+
21
+ # Local secrets / token caches (should never land in OSS repo)
22
+ .env
23
+ .env.local
24
+ *.pem
25
+ secrets/
26
+
27
+ # Coverage artefacts
28
+ .coverage
29
+ .coverage.*
30
+ coverage.xml
31
+ htmlcov/
@@ -0,0 +1,18 @@
1
+ # SPDX-License-Identifier: MIT OR Apache-2.0
2
+ # Markdownlint configuration
3
+ # See: https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md
4
+
5
+ # Disable line length rule - impractical for documentation with URLs
6
+ MD013: false
7
+
8
+ # Allow first heading to not be h1 (for templates with frontmatter)
9
+ MD041: false
10
+
11
+ # Disable table column style rule - we prefer aligned tables for readability
12
+ MD060: false
13
+
14
+ # Allow duplicate headings as long as they're not siblings.
15
+ # This is required for Keep-a-Changelog: every release section has
16
+ # its own "Added" / "Changed" / "Removed" subsections.
17
+ MD024:
18
+ siblings_only: true