slash-pro-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.
Files changed (51) hide show
  1. slash_pro_mcp-0.1.0/.gitignore +15 -0
  2. slash_pro_mcp-0.1.0/CHANGELOG.md +55 -0
  3. slash_pro_mcp-0.1.0/CONTRIBUTING.md +12 -0
  4. slash_pro_mcp-0.1.0/LICENSE +21 -0
  5. slash_pro_mcp-0.1.0/PKG-INFO +309 -0
  6. slash_pro_mcp-0.1.0/README.ko.md +96 -0
  7. slash_pro_mcp-0.1.0/README.md +284 -0
  8. slash_pro_mcp-0.1.0/RELEASING.md +15 -0
  9. slash_pro_mcp-0.1.0/SECURITY.md +28 -0
  10. slash_pro_mcp-0.1.0/pyproject.toml +68 -0
  11. slash_pro_mcp-0.1.0/src/slash_pro_mcp/__init__.py +11 -0
  12. slash_pro_mcp-0.1.0/src/slash_pro_mcp/__main__.py +81 -0
  13. slash_pro_mcp-0.1.0/src/slash_pro_mcp/client.py +397 -0
  14. slash_pro_mcp-0.1.0/src/slash_pro_mcp/common.py +170 -0
  15. slash_pro_mcp-0.1.0/src/slash_pro_mcp/config.py +216 -0
  16. slash_pro_mcp-0.1.0/src/slash_pro_mcp/instructions.py +77 -0
  17. slash_pro_mcp-0.1.0/src/slash_pro_mcp/render.py +517 -0
  18. slash_pro_mcp-0.1.0/src/slash_pro_mcp/server.py +89 -0
  19. slash_pro_mcp-0.1.0/src/slash_pro_mcp/tools/__init__.py +1 -0
  20. slash_pro_mcp-0.1.0/src/slash_pro_mcp/tools/documents.py +205 -0
  21. slash_pro_mcp-0.1.0/src/slash_pro_mcp/tools/meeting_agenda.py +60 -0
  22. slash_pro_mcp-0.1.0/src/slash_pro_mcp/tools/meetings.py +140 -0
  23. slash_pro_mcp-0.1.0/src/slash_pro_mcp/tools/outcomes.py +194 -0
  24. slash_pro_mcp-0.1.0/src/slash_pro_mcp/tools/prds.py +139 -0
  25. slash_pro_mcp-0.1.0/src/slash_pro_mcp/tools/projects.py +51 -0
  26. slash_pro_mcp-0.1.0/src/slash_pro_mcp/tools/questions.py +104 -0
  27. slash_pro_mcp-0.1.0/src/slash_pro_mcp/tools/search.py +54 -0
  28. slash_pro_mcp-0.1.0/src/slash_pro_mcp/tools/ticket_extras.py +214 -0
  29. slash_pro_mcp-0.1.0/src/slash_pro_mcp/tools/tickets.py +440 -0
  30. slash_pro_mcp-0.1.0/tests/__init__.py +0 -0
  31. slash_pro_mcp-0.1.0/tests/conftest.py +51 -0
  32. slash_pro_mcp-0.1.0/tests/fixtures/README.md +9 -0
  33. slash_pro_mcp-0.1.0/tests/fixtures/route_scopes.json +71 -0
  34. slash_pro_mcp-0.1.0/tests/helpers.py +203 -0
  35. slash_pro_mcp-0.1.0/tests/test_client.py +203 -0
  36. slash_pro_mcp-0.1.0/tests/test_config.py +220 -0
  37. slash_pro_mcp-0.1.0/tests/test_instructions.py +273 -0
  38. slash_pro_mcp-0.1.0/tests/test_security.py +242 -0
  39. slash_pro_mcp-0.1.0/tests/test_server.py +92 -0
  40. slash_pro_mcp-0.1.0/tests/test_tools_documents.py +280 -0
  41. slash_pro_mcp-0.1.0/tests/test_tools_handoffs.py +206 -0
  42. slash_pro_mcp-0.1.0/tests/test_tools_meeting_agenda.py +76 -0
  43. slash_pro_mcp-0.1.0/tests/test_tools_meetings.py +411 -0
  44. slash_pro_mcp-0.1.0/tests/test_tools_more.py +437 -0
  45. slash_pro_mcp-0.1.0/tests/test_tools_prds.py +147 -0
  46. slash_pro_mcp-0.1.0/tests/test_tools_projects.py +76 -0
  47. slash_pro_mcp-0.1.0/tests/test_tools_questions.py +186 -0
  48. slash_pro_mcp-0.1.0/tests/test_tools_relations.py +178 -0
  49. slash_pro_mcp-0.1.0/tests/test_tools_tickets_read.py +228 -0
  50. slash_pro_mcp-0.1.0/tests/test_tools_tickets_write.py +520 -0
  51. slash_pro_mcp-0.1.0/tests/test_wire_contract.py +103 -0
@@ -0,0 +1,15 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.py[cod]
4
+ .pytest_cache/
5
+ .ruff_cache/
6
+ *.egg-info/
7
+ build/
8
+ dist/
9
+ .coverage
10
+ .env
11
+ .env.*
12
+ token
13
+ .omc/
14
+ .claude/
15
+ .DS_Store
@@ -0,0 +1,55 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the project uses [Semantic Versioning](https://semver.org/).
5
+
6
+ ## [0.1.0] - 2026-11-10
7
+
8
+ ### Changed
9
+ - Wiki is now called documents. Tools renamed: `wiki_tree` → `document_tree`, `get_wiki_page` → `get_document`,
10
+ `search_wiki` → `search_documents`, `write_wiki_page` → `write_document`, `create_wiki_page` → `create_document`.
11
+ The tools call the server's new `/documents/...` routes (needs a SLASH server with the document rename).
12
+ - Tool group `wiki` is now `documents`; token scopes are documented as `document:read` / `document:write`
13
+ (tokens holding the old `wiki:*` scopes keep working).
14
+
15
+ - `search_documents` uses the server's ranked document search (`GET /documents/search`: title/body BM25,
16
+ title match, recent use) instead of reading pages and matching client-side. `project_key` is optional
17
+ (whole workspace without it); `page_id` still lists matching lines in one page.
18
+
19
+ ### Added
20
+ - First public release: a stdio MCP server (`slash-pro-mcp`, server name `slash-pro`) with 50 tools:
21
+ - tickets, verification, handoffs and readiness questions
22
+ - meetings, documents, PRDs and projects
23
+ - outcomes: `list_outcomes`, `get_outcome` (key or id), `create_outcome`, `update_outcome`, `add_outcome_evidence`, `add_ticket_to_outcome`, `remove_ticket_from_outcome`
24
+ - ticket extras:
25
+ - `replace_checklist`: agent rows only; people's rows and review results are preserved
26
+ - `list_evidence`, `add_evidence`, and `delete_evidence` (this session's evidence only)
27
+ - `update_note` / `delete_note` (only notes this agent wrote in the current session)
28
+ - `delete_relation`
29
+ - `search` (`person`: one member's tickets, docs, outcomes and meetings); `assignee`/`person` accept `me` (the token owner); `get_meeting(part=overview|minutes|summary)`; `list_meetings(upcoming=True)`
30
+ - `update_ticket` (status, assignee, due date); `update_handoff(action=claim|heartbeat|complete|block)`
31
+ - AI doc updates: `list_doc_updates`, `resolve_doc_update(action=accept|revert|reject)`, `accept_all_doc_updates`, `refresh_doc_update`; page-changing actions go through the workspace-rules-page guard
32
+ - `SLASH_PRO_TOOLS`: register only the named tool groups (e.g. `tickets,documents`); default all.
33
+ - Tool results and tool error messages are in Korean (identifiers, enum values, parameter names and ticket keys unchanged); tool descriptions stay in English.
34
+ - English tool descriptions limited to API semantics, MCP tool annotations (`readOnlyHint` / `destructiveHint` / `idempotentHint`), and `serverInfo.version` set to the package version.
35
+ - `add_verification` takes a typed report matching the server's schema (enums visible in the JSON schema).
36
+ - `create_ticket` / `create_prd` report the new key or id even when a follow-up step fails; `create_prd` fills the server's current skeleton headings.
37
+ - `canceled` cannot be set through MCP (it needs a reason, chosen in the web app); handoff claims and notes are recorded under the token's label; `list_handoffs` has no default recipient unless `SLASH_PRO_AGENT` is set and shows what blocks each handoff.
38
+ - API errors include the server's error `code` and up to 10 `candidates`.
39
+ - `list_tickets` covers one project or the whole workspace (one server-filtered call per status), with `assignee`, `blocked` and `limit` (default 50, max 200, "… 외 N개" footer), sorted newest-created first.
40
+ - `SLASH_PRO_*` configuration with `https://echo-api.slash.pro` as the default API URL.
41
+ - Security hardening:
42
+ - HTTPS-only API URL (loopback HTTP allowed for development), UUID workspace id
43
+ - `chmod 600` token files and token character validation
44
+ - token redaction
45
+ - no redirects, explicit timeouts and a 10 MB response cap
46
+ - validated, percent-encoded path segments
47
+ - the API host is limited to `echo-api.slash.pro` unless `SLASH_PRO_ALLOW_CUSTOM_API` names the exact host (dev/self-host; `=1` is refused); a custom host accepts only a literal `SLASH_PRO_TOKEN`, never a token file
48
+ - tool results capped at 200,000 characters and API error text at 2,000 characters plus 20 field errors; server-returned ids, transport errors and server warnings never reach the agent unfenced or unredacted
49
+ - proxy/CA environment variables ignored, compressed responses refused, a 60 s overall deadline per request
50
+ - server-returned ids validated before use in paths
51
+ - untrusted-content fencing (per-call random tag) for user-written content and server error messages
52
+ - workspace rules (title and body) fenced behind a constant limiting preamble and read at startup within 3 s so the handshake is never held up; agent writes to the rules page refused by canonical UUID, looked up again before every guarded write and failing closed; `SLASH_PRO_WORKSPACE_RULES=0` keeps the body out but the page protected
53
+ - loopback API hosts count as custom hosts (opt-in, literal token only)
54
+ - write confirmations that include workspace text are fenced; a 120 s overall deadline per tool call; `https` only for outcome evidence URLs
55
+ - client-side guards (own notes/evidence, checklist merge, no `canceled`) documented as a safety net, not a security boundary
@@ -0,0 +1,12 @@
1
+ # Contributing
2
+
3
+ Thanks for helping! Issues and pull requests are welcome.
4
+
5
+ - Setup: `uv sync`. Tests: `uv run pytest -q`. Lint: `uv run ruff check && uv run ruff format --check`.
6
+ - Keep the server thin: one tool per REST call. The API is the source of truth for permissions; the few client-side guards (own notes and evidence, checklist merge, no `canceled`) are a safety net for well-behaved agents, not a security boundary.
7
+ - Tool descriptions are English and describe API semantics only; team process rules belong in the workspace rules page.
8
+ - Do not add tools for human-only actions (re-parenting, merges, outcome judgements, answering questions, cancelling, token management).
9
+ - Every path segment that comes from a tool argument goes through `client.path_segment`. User-written content returned to the model goes through `render.untrusted`.
10
+ - Add a test with the httpx `MockTransport` fake (`tests/helpers.py`) for every behaviour change. Use obviously fake ids (`00000000-0000-7000-8000-0000000000xx`), `example.com` addresses and placeholder names.
11
+ - Never commit tokens, real workspace ids or internal URLs. CI runs gitleaks.
12
+ - Security issues: see [SECURITY.md](https://github.com/sigcrew/slash-pro-mcp/blob/main/SECURITY.md). Please don't open a public issue for them.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 SIG Inc.
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,309 @@
1
+ Metadata-Version: 2.5
2
+ Name: slash-pro-mcp
3
+ Version: 0.1.0
4
+ Summary: MCP server for SLASH: read and write tickets, meetings and documents from AI coding agents
5
+ Project-URL: Homepage, https://github.com/sigcrew/slash-pro-mcp
6
+ Project-URL: Issues, https://github.com/sigcrew/slash-pro-mcp/issues
7
+ Project-URL: Changelog, https://github.com/sigcrew/slash-pro-mcp/blob/main/CHANGELOG.md
8
+ Author: SIG Inc.
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: agents,mcp,model-context-protocol,slash-pro
12
+ Classifier: Development Status :: 4 - Beta
13
+ Classifier: Environment :: Console
14
+ Classifier: Intended Audience :: Developers
15
+ Classifier: Operating System :: OS Independent
16
+ Classifier: Programming Language :: Python :: 3
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Programming Language :: Python :: 3.13
19
+ Classifier: Topic :: Office/Business :: Groupware
20
+ Classifier: Topic :: Software Development
21
+ Requires-Python: >=3.12
22
+ Requires-Dist: httpx<1,>=0.28
23
+ Requires-Dist: mcp<2,>=1.23
24
+ Description-Content-Type: text/markdown
25
+
26
+ # slash-pro-mcp
27
+
28
+ [한국어](https://github.com/sigcrew/slash-pro-mcp/blob/main/README.ko.md)
29
+
30
+ An [MCP](https://modelcontextprotocol.io) server for [SLASH](https://app.slash.pro). It lets AI coding agents (Claude Code, Codex, Cursor, VS Code Copilot and others) read and write your workspace's tickets, meetings, PRDs and documents.
31
+
32
+ It is a thin local **stdio** client. Each tool makes one REST call (or a few) to the SLASH API, authenticated with **your personal API token**. The server enforces authorization; this package adds no permissions of its own, and its few extra limits are a safety net, not a security boundary (see [Security model](#security-model)).
33
+
34
+ ## Requirements
35
+
36
+ - [uv](https://docs.astral.sh/uv/) (provides `uvx`), or Python 3.12+ with `pipx`
37
+ - A SLASH workspace and a personal API token (`et_…`), issued in the web app's settings
38
+ - Your workspace id, which is the UUID in the web app URL
39
+
40
+ ## Quick start
41
+
42
+ 1. Save the token to a file only you can read. This prompts for the token without showing it or putting it in your shell history:
43
+
44
+ ```bash
45
+ (umask 077; mkdir -p ~/.config/slash-pro; printf 'Paste token, then Enter: '; read -rs T; echo; printf '%s' "$T" > ~/.config/slash-pro/token); ls -l ~/.config/slash-pro/token
46
+ ```
47
+
48
+ The last line should start with `-rw-------`. On macOS and Linux the server refuses to start if the token file is accessible by group or others. Windows has no such permission check, so keep the file in your user profile.
49
+
50
+ 2. Register the server with your agent (see [Client setup](#client-setup)). With Claude Code:
51
+
52
+ ```bash
53
+ claude mcp add slash-pro -s user \
54
+ -e SLASH_PRO_WORKSPACE_ID=00000000-0000-0000-0000-000000000000 \
55
+ -- uvx slash-pro-mcp==0.1.0
56
+ ```
57
+
58
+ 3. Ask your agent something like *"list my in-progress tickets"*.
59
+
60
+ Check the install without an agent: `uvx slash-pro-mcp==0.1.0 --help`.
61
+
62
+ The snippets pin the version (`slash-pro-mcp==0.1.0`) so a new release never runs without you choosing it. Bump the pin deliberately after reading the [changelog](https://github.com/sigcrew/slash-pro-mcp/blob/main/CHANGELOG.md).
63
+
64
+ ## Configuration
65
+
66
+ Set these environment variables in the agent's MCP config.
67
+
68
+ | Variable | Default | Meaning |
69
+ |---|---|---|
70
+ | `SLASH_PRO_WORKSPACE_ID` | — (required) | Workspace UUID |
71
+ | `SLASH_PRO_TOKEN` | — | Personal API token. If you leave it unset, the token is read from a file |
72
+ | `SLASH_PRO_TOKEN_FILE` | `~/.config/slash-pro/token` | File holding the token. Must be `chmod 600` |
73
+ | `SLASH_PRO_API_URL` | `https://echo-api.slash.pro` | API root. Must be `https://echo-api.slash.pro` (any path) unless a custom host is allowed. The host must be lowercase ASCII |
74
+ | `SLASH_PRO_ALLOW_CUSTOM_API` | — | **Development / self-hosting only.** Set to the exact host to allow, e.g. `localhost` or `api.example.com` (`1` is refused). Loopback (`localhost`, `127.0.0.1`, `[::1]`) also needs this and is the only place plain `http://` is allowed. The token must then be a literal `SLASH_PRO_TOKEN`; no token file (default or `SLASH_PRO_TOKEN_FILE`) is ever read for a custom host |
75
+ | `SLASH_PRO_WORKSPACE_RULES` | `1` | Set to `0` to keep the workspace rules page out of the server instructions. The page stays protected from agent writes |
76
+ | `SLASH_PRO_TOOLS` | all | Comma-separated tool groups to register, to keep the tool list (and its context cost) small: `projects`, `tickets`, `ticket_extras`, `questions`, `meetings`, `meeting_agenda`, `documents`, `doc_updates`, `prds`, `outcomes`, `search`. Unknown names stop the server |
77
+ | `SLASH_PRO_AGENT` | — | Recipient label for `list_handoffs` when `to` is not given (aliases match, e.g. `codex` = `Codex`). Unset: `list_handoffs` shows handoffs to every recipient. Claims and notes are always recorded under the token's own label |
78
+ | `SLASH_PRO_AGENT_MODEL` | — | Model alias, sent as `X-Agent-Model` so the activity log records which model acted |
79
+ | `SLASH_PRO_REQUESTED_BY` | — | Overrides the requester shown on writes. By default the server derives it from the token owner |
80
+
81
+ Prefer `SLASH_PRO_TOKEN_FILE` (or the default file) over `SLASH_PRO_TOKEN`. That keeps the secret out of config files that are often committed or synced.
82
+
83
+ > **Never put a literal token in a project-level config file** such as `.cursor/mcp.json`, `.vscode/mcp.json` or `.mcp.json`. Those files get committed. Use the token file, an `${env:…}` / `${input:…}` reference, or your user-level config.
84
+
85
+ ## Client setup
86
+
87
+ Every client runs the same command, `uvx slash-pro-mcp==0.1.0`. Some GUI apps don't inherit your shell's `PATH`. If yours can't find `uvx`, use its absolute path (run `which uvx` to find it).
88
+
89
+ ### Claude Code
90
+
91
+ ```bash
92
+ claude mcp add slash-pro -s user \
93
+ -e SLASH_PRO_WORKSPACE_ID=<workspace-uuid> \
94
+ -- uvx slash-pro-mcp==0.1.0
95
+ claude mcp list
96
+ ```
97
+
98
+ ### Codex CLI — `~/.codex/config.toml`
99
+
100
+ ```toml
101
+ [mcp_servers.slash-pro]
102
+ command = "uvx"
103
+ args = ["slash-pro-mcp==0.1.0"]
104
+ # The first run downloads the package; give it more than Codex's 10 s default.
105
+ startup_timeout_sec = 30
106
+ # Forward the token from your shell instead of writing it here (optional):
107
+ # env_vars = ["SLASH_PRO_TOKEN"]
108
+
109
+ [mcp_servers.slash-pro.env]
110
+ SLASH_PRO_WORKSPACE_ID = "<workspace-uuid>"
111
+ SLASH_PRO_AGENT = "Codex"
112
+ ```
113
+
114
+ The CLI equivalent is `codex mcp add slash-pro --env SLASH_PRO_WORKSPACE_ID=<workspace-uuid> -- uvx slash-pro-mcp==0.1.0` (then add `startup_timeout_sec` to the generated entry).
115
+
116
+ ### Cursor — `.cursor/mcp.json` (project) or `~/.cursor/mcp.json` (global)
117
+
118
+ ```json
119
+ {
120
+ "mcpServers": {
121
+ "slash-pro": {
122
+ "type": "stdio",
123
+ "command": "uvx",
124
+ "args": ["slash-pro-mcp==0.1.0"],
125
+ "env": {
126
+ "SLASH_PRO_WORKSPACE_ID": "<workspace-uuid>",
127
+ "SLASH_PRO_AGENT": "Cursor"
128
+ }
129
+ }
130
+ }
131
+ }
132
+ ```
133
+
134
+ To pass the token from your environment instead of the token file, add `"SLASH_PRO_TOKEN": "${env:SLASH_PRO_TOKEN}"`.
135
+
136
+ ### VS Code / GitHub Copilot — `.vscode/mcp.json`
137
+
138
+ VS Code uses a top-level **`servers`** key, not `mcpServers`. An `inputs` entry with `"password": true` makes VS Code prompt for the token once and store it securely, so it never lands in the file:
139
+
140
+ ```json
141
+ {
142
+ "inputs": [
143
+ {
144
+ "type": "promptString",
145
+ "id": "slash-pro-token",
146
+ "description": "SLASH personal API token (et_...)",
147
+ "password": true
148
+ }
149
+ ],
150
+ "servers": {
151
+ "slash-pro": {
152
+ "type": "stdio",
153
+ "command": "uvx",
154
+ "args": ["slash-pro-mcp==0.1.0"],
155
+ "env": {
156
+ "SLASH_PRO_WORKSPACE_ID": "<workspace-uuid>",
157
+ "SLASH_PRO_TOKEN": "${input:slash-pro-token}",
158
+ "SLASH_PRO_AGENT": "Copilot"
159
+ }
160
+ }
161
+ }
162
+ }
163
+ ```
164
+
165
+ ### Claude Desktop — `claude_desktop_config.json`
166
+
167
+ On macOS the file is `~/Library/Application Support/Claude/claude_desktop_config.json`. On Windows it is `%APPDATA%\Claude\claude_desktop_config.json`.
168
+
169
+ ```json
170
+ {
171
+ "mcpServers": {
172
+ "slash-pro": {
173
+ "command": "/absolute/path/to/uvx",
174
+ "args": ["slash-pro-mcp==0.1.0"],
175
+ "env": {
176
+ "SLASH_PRO_WORKSPACE_ID": "<workspace-uuid>",
177
+ "SLASH_PRO_AGENT": "Claude Desktop"
178
+ }
179
+ }
180
+ }
181
+ }
182
+ ```
183
+
184
+ ### Gemini CLI — `~/.gemini/settings.json`
185
+
186
+ ```json
187
+ {
188
+ "mcpServers": {
189
+ "slash-pro": {
190
+ "command": "uvx",
191
+ "args": ["slash-pro-mcp==0.1.0"],
192
+ "env": {
193
+ "SLASH_PRO_WORKSPACE_ID": "<workspace-uuid>",
194
+ "SLASH_PRO_AGENT": "Gemini CLI"
195
+ }
196
+ }
197
+ }
198
+ }
199
+ ```
200
+
201
+ Gemini CLI expands `$VAR` / `${VAR}` in `env`, so `"SLASH_PRO_TOKEN": "$SLASH_PRO_TOKEN"` also works. The CLI equivalent is `gemini mcp add -e SLASH_PRO_WORKSPACE_ID=<workspace-uuid> slash-pro uvx slash-pro-mcp==0.1.0`.
202
+
203
+ ### Windsurf — `~/.codeium/windsurf/mcp_config.json`
204
+
205
+ ```json
206
+ {
207
+ "mcpServers": {
208
+ "slash-pro": {
209
+ "command": "uvx",
210
+ "args": ["slash-pro-mcp==0.1.0"],
211
+ "env": {
212
+ "SLASH_PRO_WORKSPACE_ID": "<workspace-uuid>",
213
+ "SLASH_PRO_AGENT": "Windsurf"
214
+ }
215
+ }
216
+ }
217
+ }
218
+ ```
219
+
220
+ ### Any other stdio client
221
+
222
+ Run `uvx slash-pro-mcp==0.1.0` (or `python -m slash_pro_mcp` inside an environment where the package is installed) with the environment variables above. The server speaks MCP over stdin/stdout and logs only to stderr.
223
+
224
+ ## Tools
225
+
226
+ Tools return markdown. Output that contains text from the workspace is wrapped in an untrusted-content fence (see [Security model](#security-model)). Server errors come back as tool errors carrying the API's message, error code and candidates (`SLASH API 오류:` + `HTTP 409: …`), also fenced. Each tool carries MCP annotations (`readOnlyHint`, `destructiveHint`, `idempotentHint`). Tool results and tool error messages are in Korean, the product's primary language (identifiers, enum values, parameter names and ticket keys stay as they are, e.g. `알 수 없는 status: merged (허용: backlog, …)`); tool descriptions and parameter schemas are in English.
227
+
228
+ | Area | Tool | Kind | What it does |
229
+ |---|---|---|---|
230
+ | Tickets | `list_tickets` | read | Tickets for one project or the whole workspace, filtered by status, assignee, blocked and PRD (one server-filtered call per wanted status, merged). Newest-created first (ties by id); at most `limit` rows (default 50, max 200) plus a "… 외 N개" line |
231
+ | | `get_ticket` | read | Full working context for `KEY-N`: description, acceptance, evidence, relations, handoffs, activity |
232
+ | | `create_ticket` | write | Create a ticket, sub-ticket (`parent`) or follow-up (`follows`). If a step after creation fails, the result still names the new key |
233
+ | | `update_ticket` | write | Status, assignee and due date. Status: `backlog` · `todo` · `in_progress` · `review` · `done` (`canceled` needs a reason: web app). Who may move tickets to `done` is a workspace rule, not enforced here |
234
+ | | `add_note` | write | Timeline note |
235
+ | | `relate_ticket` | write | `follows` / `blocks` relation |
236
+ | | `mark_deployed` | write | Idempotent `vX으로 배포됨` ("deployed in vX") system note |
237
+ | | `delete_relation` | write | Remove a `follows` / `blocks` relation to another ticket |
238
+ | | `replace_checklist` | write | Replace the agent-owned checklist rows (`owner: agent`, written by any agent); people's and unowned rows and review results are kept, and dropping or rewording a reviewed row is refused |
239
+ | | `list_evidence` | read | The ticket's evidence thread (pinned transcript excerpts) |
240
+ | | `add_evidence` · `delete_evidence` | write | Pin a transcript excerpt / remove evidence this agent added in the current session |
241
+ | | `update_note` · `delete_note` | write | Edit a plain note / delete any note this agent wrote in the current session. Handoff and verification bodies can't be edited; the server allows author edits only within 10 minutes |
242
+ | Outcomes | `list_outcomes` · `get_outcome` | read | Outcomes of a project; one outcome by key (`CORE-45`) or id |
243
+ | | `create_outcome` · `update_outcome` | write | Create (`draft` / `executing` / `paused`) or edit fields (revision checked) |
244
+ | | `add_outcome_evidence` | write | Evidence for an outcome |
245
+ | | `add_ticket_to_outcome` · `remove_ticket_from_outcome` | write | Ticket membership (`tickets:read`, `tickets:write` and `document:read`); `move=True` moves a ticket from another outcome |
246
+ | Search | `search` | read | Workspace search over tickets, outcomes, docs and meetings (titles and content); `person` narrows to one member (ticket assignee or creator) |
247
+ | Verification | `start_verification` | write | Pin commits and answers before verifying |
248
+ | | `add_verification` | write | Structured verification report (typed schema matching the server's) |
249
+ | Handoffs | `add_handoff` | write | Structured handoff to another agent or role |
250
+ | | `list_handoffs` | read | Handoff inbox for `to` / `SLASH_PRO_AGENT`, or for everyone when neither is set; shows what blocks each |
251
+ | | `update_handoff` | write | Handoff lifecycle: `claim` · `heartbeat` · `complete` · `block` (claims are atomic and leased) |
252
+ | Readiness | `ask_questions` | write | Ask the ticket owner up to 4 questions |
253
+ | | `list_questions` | read | Questions on one ticket (any state), or the open questions a person should answer |
254
+ | | `readiness_refresh` | write | Re-judge remaining assumptions (rate-limited) |
255
+ | Meetings | `list_meetings` | read | Find meetings by date, title, series or attendee; `upcoming=True`: scheduled meetings, soonest first |
256
+ | | `get_meeting` | read | `part=overview`: summary, attendees, transcript and analysis status; `minutes`: latest minutes as markdown; `summary`: executive summary and check points |
257
+ | | `find_transcript_excerpts` | read | Transcript passages that support a statement (server-side LLM call) |
258
+ | | `add_todo` | write | Add an approved to-do to a meeting |
259
+ | | `add_agenda_item` | write | Agenda line for the next occurrence of a recurring meeting |
260
+ | Documents | `document_tree` | read | A project's page tree |
261
+ | | `get_document` | read | Page body (plain text or markdown) |
262
+ | | `search_documents` | read | Documents ranked by the server (title/body match, recent use), optionally in one project; or matching lines in one page |
263
+ | | `write_document` | write | Append to or replace a page body |
264
+ | | `create_document` | write | New page under a section root |
265
+ | | `list_doc_updates` | read | AI doc-update proposals for a page or produced by a meeting (by meeting: `document:read` and `meetings:read`) |
266
+ | | `resolve_doc_update` · `accept_all_doc_updates` | write | Accept, revert or reject one AI doc update (checked against its page) / accept all of a page's (never on the workspace rules page) |
267
+ | | `refresh_doc_update` | write | Re-check a proposal against the latest document |
268
+ | PRDs | `list_prds` · `get_prd` | read | PRDs and their tickets |
269
+ | | `create_prd` | write | New PRD (the server's skeleton sections or markdown) |
270
+ | | `assign_ticket_prd` | write | Attach a ticket to a PRD or detach it |
271
+ | Projects | `create_project` · `update_project` | write | Needs the `projects:write` scope |
272
+
273
+ Some actions are **human-only on purpose**, and no tools exist for them: re-parenting tickets, merges, outcome stage transitions, stop reasons and judgements, outcome related tickets and documents, promoting tickets to outcomes, answering readiness questions, cancelling tickets, archiving or deleting projects, and token management.
274
+
275
+ ## Security model
276
+
277
+ - **Your token is the boundary.** The server checks every call against the token's scopes and the owner's workspace membership. Issue a token with only the scopes your agent needs:
278
+ - read-only: `tickets:read`, `document:read`, `meetings:read`
279
+ - typical agent: add `tickets:write` and `document:write`
280
+ - `projects:write` lets the token rename or re-describe **every** project in the workspace. Grant it only when needed.
281
+ - `meetings:write` and `recordings:write` can trigger AI and transcription cost. This package doesn't need them for most tools.
282
+
283
+ Use one token per agent and label it with the agent's name. Never share tokens. Tokens expire, so revoke and reissue them in the web app.
284
+ - **Token handling.** The token is read from the environment or a `chmod 600` file. On macOS and Linux the server refuses group/world-accessible token files (Windows has no such check); it refuses tokens with whitespace or control characters everywhere. The token is never logged, never put in `repr`, error text or tool output, and is redacted if a response ever includes it. httpx, httpcore and mcp logging is kept at WARNING.
285
+ - **Where the token can go.** Only `echo-api.slash.pro` is accepted as the API host. Any other host, loopback included, needs `SLASH_PRO_ALLOW_CUSTOM_API=<that exact host>` (development / self-hosting only) and then accepts only a literal `SLASH_PRO_TOKEN` — token files are never read for a custom host, so editing the URL in a config file cannot send your saved token file elsewhere. Residual risk: a project-level config that sets a custom host could still reference a `SLASH_PRO_TOKEN` you exported in your shell (for example `${env:SLASH_PRO_TOKEN}`), so prefer the token file over exporting the token, and review project MCP configs before trusting them. Hosts must be lowercase ASCII (no IDN, backslashes, `;`, spaces or credentials). Configuration errors show only `scheme://host`.
286
+ - **Transport.** HTTPS only (plain HTTP works only for loopback during development), and TLS verification is always on with no option to turn it off. Proxy and custom-CA environment variables (`HTTPS_PROXY`, `SSL_CERT_FILE`, …) are **ignored on purpose** (`trust_env=False`), so the environment cannot reroute or intercept the token. Redirects are never followed. Each request has a 10 s connect timeout, a 30 s read timeout and an overall 60 s deadline; each tool call has an overall 120 s deadline. Responses are requested uncompressed (a compressed reply is refused before its body is read) and capped at 10 MB.
287
+ - **Input hygiene.** Ids and ticket keys are validated and percent-encoded before they go into a URL path — both those from tool arguments and those returned by the server. A model can't inject path traversal (`../`) or query strings (`?x=`). The workspace id must be a UUID.
288
+ - **Prompt injection.** Tickets, documents, minutes, transcripts, titles, handoffs, questions, server warnings and member names are written by people, including meeting participants outside your team. Every tool result that includes such text (read results and write confirmations that include titles, names or warnings) is returned inside a `<untrusted-workspace-content-XXXXXXXX source="…">` fence, with a fresh random suffix on every call so content can't forge the closing tag. Results made only of ids, keys and statuses (`add_note`, `add_handoff`, `add_evidence`, `update_note`, `mark_deployed`, the delete tools) are not fenced; ids the server returns are shown only if they are UUIDs or plain id strings, otherwise fenced, and an invalid id in a URL path is reported without repeating it. Server error messages (`source="api error"`, at most 2,000 characters plus 20 field errors), transport error details (`source="transport error"`) and member names in assignee-lookup errors (`source="members"`) are fenced too. A tool result longer than 200,000 characters is cut with a `… truncated` note. The server instructions tell the agent to treat fenced text as data, not instructions. This reduces the risk but does not remove it. Review what an agent writes back to your workspace, and keep write scopes off tokens used by agents that also read untrusted sources.
289
+ - **Workspace rules.** At startup the server reads the workspace's designated "agent instructions" document into the MCP `instructions`, giving up after 3 seconds so the client handshake is never held up (it then starts without the rules and logs a warning to stderr). Because every agent reads that text, the page title and body are placed together in a fence after a constant preamble: the rules are team process conventions for tickets and notes, and can never authorize running shell commands, installing software, reading or sending credentials or files, or contacting other hosts. This server refuses agent writes to that page (`이 페이지는 웹 앱에서 사람만 고칠 수 있음`): before every guarded write (`write_document`, `create_document` for the product page, `create_prd` with markdown, and accepting, reverting or rejecting AI doc updates) it looks the rules page up again and compares canonical UUIDs, so a page designated after startup or an alternate spelling of the id doesn't slip through. If that lookup fails, the write is refused (fail closed). `SLASH_PRO_WORKSPACE_RULES=0` keeps the rules out of the instructions; the page stays protected.
290
+ - **Client-side guards are a safety net, not a security boundary.** This client adds a few limits of its own (for example, it only edits or deletes notes and evidence it created, keeps people's and reviewed checklist rows, and refuses `canceled`) so a well-behaved agent doesn't damage people's work by mistake. Authorization is decided by the SLASH API from the token's scopes. Scope tokens narrowly, keep write scopes off agents that also read untrusted sources, and don't give untrusted agents shell access to the token file or environment.
291
+ - **No telemetry.** The only network destination is the configured API URL.
292
+ - **Releases.** Releases are published from tags by GitHub Actions with PyPI Trusted Publishing and build provenance attestations; the release job checks that the tag points to a commit on `main`. Maintainers should require reviewers on the `pypi` environment and protect `v*` tags.
293
+
294
+ See [SECURITY.md](https://github.com/sigcrew/slash-pro-mcp/blob/main/SECURITY.md) to report a vulnerability.
295
+
296
+ ## Development
297
+
298
+ ```bash
299
+ uv sync
300
+ uv run pytest -q
301
+ uv run ruff check && uv run ruff format --check
302
+ uv build
303
+ ```
304
+
305
+ The tests fake the API with an httpx `MockTransport` and need no network or account.
306
+
307
+ ## License
308
+
309
+ [MIT](https://github.com/sigcrew/slash-pro-mcp/blob/main/LICENSE) © SIG Inc.
@@ -0,0 +1,96 @@
1
+ # slash-pro-mcp
2
+
3
+ [English](https://github.com/sigcrew/slash-pro-mcp/blob/main/README.md)
4
+
5
+ [SLASH](https://app.slash.pro)용 [MCP](https://modelcontextprotocol.io) 서버입니다. Claude Code·Codex·Cursor·VS Code Copilot 같은 AI 코딩 에이전트가 워크스페이스의 티켓·회의·PRD·문서를 읽고 쓸 수 있게 해 줍니다.
6
+
7
+ 로컬 **stdio** 클라이언트이고, 도구 하나가 SLASH REST 호출 하나(또는 몇 개)를 감쌉니다. 인증은 **본인의 개인 API 토큰**으로 합니다. 권한은 서버가 판단하고, 이 패키지는 권한을 따로 더하지 않습니다. 이 패키지가 더하는 몇 가지 제한은 안전망일 뿐 보안 경계가 아닙니다([보안](#보안) 참고).
8
+
9
+ ## 준비
10
+
11
+ - [uv](https://docs.astral.sh/uv/)(`uvx` 포함) 또는 Python 3.12+와 `pipx`
12
+ - SLASH 워크스페이스와 개인 API 토큰(`et_…`) — 웹 앱 설정에서 발급
13
+ - 워크스페이스 id — 웹 앱 주소에 있는 UUID
14
+
15
+ ## 빠른 시작
16
+
17
+ ```bash
18
+ # 토큰을 화면에 보이지 않게 입력받아 셸 기록에 남기지 않고 본인만 읽을 수 있는 파일로 저장
19
+ # 마지막 줄이 -rw------- 로 시작하면 정상
20
+ (umask 077; mkdir -p ~/.config/slash-pro; printf '토큰 붙여넣고 Enter: '; read -rs T; echo; printf '%s' "$T" > ~/.config/slash-pro/token); ls -l ~/.config/slash-pro/token
21
+
22
+ claude mcp add slash-pro -s user \
23
+ -e SLASH_PRO_WORKSPACE_ID=<워크스페이스-uuid> \
24
+ -- uvx slash-pro-mcp==0.1.0
25
+ ```
26
+
27
+ macOS·Linux에서는 토큰 파일을 그룹·다른 사용자가 읽을 수 있으면 서버가 시작을 거부합니다. Windows에는 이 권한 검사가 없으니 사용자 프로필 안에 두세요.
28
+
29
+ 설치 확인: `uvx slash-pro-mcp==0.1.0 --help`. 예시는 버전을 고정합니다(`slash-pro-mcp==0.1.0`). 새 버전은 [변경 기록](https://github.com/sigcrew/slash-pro-mcp/blob/main/CHANGELOG.md)을 확인한 뒤 직접 올리세요.
30
+
31
+ Codex는 서버 시작을 기본 10초만 기다리므로 첫 실행(패키지 내려받기)을 위해 `~/.codex/config.toml`에 `startup_timeout_sec = 30`을 넣으세요:
32
+
33
+ ```toml
34
+ [mcp_servers.slash-pro]
35
+ command = "uvx"
36
+ args = ["slash-pro-mcp==0.1.0"]
37
+ startup_timeout_sec = 30
38
+
39
+ [mcp_servers.slash-pro.env]
40
+ SLASH_PRO_WORKSPACE_ID = "<워크스페이스-uuid>"
41
+ ```
42
+
43
+ ## 설정
44
+
45
+ | 변수 | 기본값 | 뜻 |
46
+ |---|---|---|
47
+ | `SLASH_PRO_WORKSPACE_ID` | (필수) | 워크스페이스 UUID |
48
+ | `SLASH_PRO_TOKEN` | — | 개인 API 토큰. 없으면 파일에서 읽음 |
49
+ | `SLASH_PRO_TOKEN_FILE` | `~/.config/slash-pro/token` | 토큰 파일 (`chmod 600` 필수) |
50
+ | `SLASH_PRO_API_URL` | `https://echo-api.slash.pro` | API 주소. 커스텀 호스트를 허용하지 않았다면 `https://echo-api.slash.pro`(경로는 자유)만 허용. 호스트는 소문자 ASCII |
51
+ | `SLASH_PRO_ALLOW_CUSTOM_API` | — | **개발·자체 호스팅 전용.** 허용할 호스트를 정확히 적음(예: `localhost`, `api.example.com`; `1`은 거부). 루프백(localhost·127.0.0.1·[::1])도 이 설정이 필요하고, `http://`는 루프백에서만 허용. 이때 토큰은 `SLASH_PRO_TOKEN` 값으로만 받고, 토큰 파일(기본·이전·`SLASH_PRO_TOKEN_FILE`)은 절대 읽지 않음 |
52
+ | `SLASH_PRO_WORKSPACE_RULES` | `1` | `0`이면 규칙 본문을 instructions에 넣지 않음(에이전트 편집 차단은 그대로) |
53
+ | `SLASH_PRO_TOOLS` | 전체 | 등록할 툴 그룹(쉼표 구분). 툴 목록과 컨텍스트 비용을 줄일 때: `projects`, `tickets`, `ticket_extras`, `questions`, `meetings`, `meeting_agenda`, `documents`, `doc_updates`, `prds`, `outcomes`, `search`. 모르는 이름이면 시작하지 않음 |
54
+ | `SLASH_PRO_AGENT` | — | `list_handoffs`에 `to`가 없을 때 볼 받는 이 라벨. 없으면 모든 받는 이의 인계를 보여 줌. 맡기·노트는 항상 토큰 라벨로 기록 |
55
+ | `SLASH_PRO_AGENT_MODEL` | — | 모델 별칭. `X-Agent-Model`로 보내 활동 기록에 남김 |
56
+ | `SLASH_PRO_REQUESTED_BY` | — | 요청자 표시를 명시적으로 덮어쓸 때만 사용. 기본은 서버가 토큰 주인으로 정함 |
57
+
58
+ > **토큰을 프로젝트 설정 파일(`.cursor/mcp.json`·`.vscode/mcp.json`·`.mcp.json`)에 직접 적지 마세요.** 이런 파일은 커밋됩니다. 토큰 파일, `${env:…}`·`${input:…}` 참조, 사용자 단위 설정을 쓰세요.
59
+
60
+ ## 클라이언트별 설정
61
+
62
+ Codex·Cursor·VS Code·Claude Desktop·Gemini CLI·Windsurf 설정 예시는 [README.md › Client setup](https://github.com/sigcrew/slash-pro-mcp/blob/main/README.md#client-setup)에 있습니다(모두 `uvx slash-pro-mcp==0.1.0`). VS Code는 최상위 키가 `servers`이고, `inputs`에 `"password": true`를 주면 토큰을 파일에 적지 않고 입력받아 안전하게 저장합니다.
63
+
64
+ ## 도구
65
+
66
+ 전체 도구 표는 [README.md › Tools](https://github.com/sigcrew/slash-pro-mcp/blob/main/README.md#tools)에 있습니다. 도구 결과와 도구 오류 메시지는 한국어이고(식별자·enum 값·인자 이름·티켓 키는 그대로), 도구 설명과 인자 스키마는 영어입니다. 묶음별로 보면:
67
+
68
+ | 묶음 | 도구 |
69
+ |---|---|
70
+ | 티켓 | `list_tickets`(프로젝트 또는 워크스페이스 전체, 상태·담당·막힘·PRD 필터(상태마다 서버 필터 호출 후 합침), 만든 시각 최신순, 기본 50·최대 200개 + "N개 더" 줄) · `get_ticket` · `create_ticket` · `update_ticket`(상태·담당·기한. 상태는 backlog·todo·in_progress·review·done — canceled는 사유가 필요해 웹에서. done을 누가 넘길지는 워크스페이스 규칙) · `add_note` · `update_note`(이 세션의 일반 노트만, 서버는 작성 10분 안에만 허용) · `delete_note`(이 세션에서 이 에이전트가 쓴 노트만) · `relate_ticket` · `delete_relation` · `replace_checklist`(에이전트 항목만 — 다른 에이전트가 쓴 판정 없는 항목도 바뀜, 사람 항목·리뷰 판정 유지, 판정 있는 항목은 빼거나 문구를 바꿀 수 없음) · `list_evidence` · `add_evidence` · `delete_evidence`(이 세션에서 넣은 근거만) · `mark_deployed` |
71
+ | 검증·인계·준비도 | `start_verification` · `add_verification` · `add_handoff` · `list_handoffs` · `update_handoff`(claim·heartbeat·complete·block) · `ask_questions` · `list_questions` · `readiness_refresh` |
72
+ | 아웃컴 | `list_outcomes` · `get_outcome` · `create_outcome` · `update_outcome` · `add_outcome_evidence` · `add_ticket_to_outcome` · `remove_ticket_from_outcome` |
73
+ | 회의 | `list_meetings`(`upcoming=True`면 예정 회의) · `get_meeting`(`part`=overview·minutes·summary) · `find_transcript_excerpts` · `add_todo` · `add_agenda_item` |
74
+ | 문서·PRD·검색 | `document_tree` · `get_document` · `search_documents` · `write_document` · `create_document` · `list_doc_updates` · `resolve_doc_update`(accept·revert·reject) · `accept_all_doc_updates` · `refresh_doc_update` · `list_prds` · `get_prd` · `create_prd` · `assign_ticket_prd` · `search` |
75
+ | 프로젝트 | `create_project` · `update_project` |
76
+
77
+ 티켓 부모 변경·병합·아웃컴 상태 전환·중단 사유·판정·관련 티켓·문서 연결·아웃컴 승격·준비도 질문 답변·티켓 취소·프로젝트 보관/삭제·토큰 관리는 **사람만** 할 수 있는 일이라서 도구로 만들지 않았습니다. AI 문서 업데이트의 수락·되돌리기·거절은 그 업데이트의 문서(page_id)를 확인하고, 워크스페이스 규칙 페이지에는 하지 않습니다.
78
+
79
+ ## 보안
80
+
81
+ - **권한 경계는 토큰입니다.** 필요한 스코프만 골라 발급하세요. 읽기만 할 때는 `tickets:read`·`document:read`·`meetings:read`면 되고, 쓰기까지 하는 일반 에이전트라면 `tickets:write`·`document:write`를 더합니다. `projects:write`를 주면 워크스페이스의 모든 프로젝트 이름과 설명을 바꿀 수 있습니다. 토큰은 에이전트마다 하나씩 따로 발급하고 공유하지 마세요.
82
+ - **토큰 취급**: 로그·`repr`·오류·도구 결과에 토큰을 넣지 않고, 응답에 토큰이 섞여 오면 가립니다. macOS·Linux에서는 권한이 열린 토큰 파일을 거부하고(Windows는 검사 없음), 공백·제어문자가 섞인 토큰은 어디서나 거부합니다.
83
+ - **토큰이 갈 수 있는 곳**: API 호스트는 `echo-api.slash.pro`만 허용합니다. 루프백을 포함한 그 밖의 호스트는 `SLASH_PRO_ALLOW_CUSTOM_API=<그 호스트>`(개발·자체 호스팅 전용)가 필요하고, 토큰은 `SLASH_PRO_TOKEN` 값으로만 받으며 토큰 파일은 읽지 않습니다. 남는 위험: 커스텀 호스트를 지정한 프로젝트 설정이 셸에 export한 `SLASH_PRO_TOKEN`을 참조할 수는 있으니, 토큰은 export보다 토큰 파일로 두고 프로젝트 MCP 설정은 확인한 뒤 신뢰하세요. 설정 오류 메시지에는 `scheme://host`만 나옵니다.
84
+ - **전송**: HTTPS만 허용하고 TLS 검증은 항상 켜 둡니다. 프록시·CA 환경변수(`HTTPS_PROXY`·`SSL_CERT_FILE` 등)는 **일부러 무시**합니다(`trust_env=False`). 리다이렉트는 따라가지 않고, 연결 10초·읽기 30초 타임아웃과 요청 전체 60초, 도구 호출 전체 120초 기한을 둡니다. 응답은 압축 없이 받고(압축 응답은 본문을 읽기 전에 거부) 10 MB로 제한합니다.
85
+ - **입력 검증**: 경로에 들어가는 id·티켓 키는 도구 인자로 받은 것이든 서버가 돌려준 것이든 모두 검증하고 퍼센트 인코딩합니다. 그래서 `../`나 `?x=` 같은 경로·쿼리를 끼워 넣을 수 없습니다.
86
+ - **프롬프트 인젝션**: 워크스페이스의 글(티켓·회의·전사·문서·PRD·인계·질문·제목·멤버 이름·서버 경고)이 들어가는 도구 결과(쓰기 확인 문구 포함)와 서버 오류 메시지는 `<untrusted-workspace-content-XXXXXXXX source="…">` 블록으로 감쌉니다. XXXXXXXX는 호출마다 바뀌는 무작위 값이라 내용 안에서 닫는 태그를 위조할 수 없습니다. id·키·상태만 돌려주는 결과(`add_note`·`add_handoff`·`add_evidence`·`update_note`·`mark_deployed`·삭제 도구)는 감싸지 않되, 서버가 준 id는 UUID나 단순 id 문자열일 때만 그대로 보이고 아니면 감쌉니다. 경로에 쓸 수 없는 서버 id는 값을 보이지 않고 오류로 알립니다. 전송 오류 내용도 감싸고, 서버 오류 메시지는 2,000자·필드 오류 20개까지, 도구 결과는 200,000자까지로 자릅니다. 자세한 내용은 [README.md › Security model](https://github.com/sigcrew/slash-pro-mcp/blob/main/README.md#security-model). 위험을 완전히 없애지는 못하므로, 에이전트가 쓴 내용은 사람이 확인하세요.
87
+ - **워크스페이스 규칙**: 시작할 때 규칙 페이지를 읽어 instructions에 넣되 3초 안에 못 읽으면 규칙 없이 시작합니다(클라이언트 연결을 붙잡지 않음, stderr에 경고). 규칙 페이지는 모든 에이전트가 읽기 때문에, 페이지 제목과 본문을 함께 고정 안내문 뒤의 블록 안에 넣습니다. 안내문은 이 규칙이 티켓·노트 처리 관례일 뿐이며 셸 명령 실행·소프트웨어 설치·자격 증명이나 파일 읽기·전송·다른 호스트 접속은 절대 허용하지 않는다고 못박습니다. 이 서버는 그 페이지에 대한 에이전트 쓰기를 거부합니다: 보호 대상 쓰기(문서 쓰기, 제품 전략 문서, 마크다운 PRD, AI 문서 업데이트 수락·되돌리기·거절) 직전마다 규칙 페이지를 다시 조회해 정규화한 UUID로 비교하므로 시작 뒤에 지정된 페이지도 막히고, 조회에 실패하면 쓰기를 거부합니다. `SLASH_PRO_WORKSPACE_RULES=0`이면 본문만 넣지 않고 보호는 유지합니다.
88
+ - **클라이언트 쪽 제한은 안전망일 뿐 보안 경계가 아닙니다**: 이 클라이언트는 잘 동작하는 에이전트가 실수로 사람의 작업을 망치지 않도록 몇 가지 제한을 둡니다(예: 자기가 만든 노트·근거만 고치거나 지우기, 사람 항목·판정이 있는 체크리스트 항목 유지, canceled 거부). 권한은 SLASH API가 토큰 스코프로 판단합니다. 토큰 스코프는 좁게 주고, 믿을 수 없는 내용을 읽는 에이전트에게는 쓰기 스코프를 주지 말고, 믿을 수 없는 에이전트에게 토큰 파일이나 환경 변수에 닿는 셸 권한을 주지 마세요.
89
+ - **텔레메트리 없음**: 네트워크 요청은 설정한 API 주소로만 갑니다.
90
+ - **릴리스**: 태그에서 GitHub Actions가 PyPI Trusted Publishing과 빌드 출처 증명으로 배포하고, 태그 커밋이 `main`에 있는지 확인합니다. 관리자는 `pypi` 환경에 필수 리뷰어를 두고 `v*` 태그를 보호하세요.
91
+
92
+ 취약점 제보는 [SECURITY.md](https://github.com/sigcrew/slash-pro-mcp/blob/main/SECURITY.md)를 참고하세요.
93
+
94
+ ## 라이선스
95
+
96
+ [MIT](https://github.com/sigcrew/slash-pro-mcp/blob/main/LICENSE) © SIG Inc.