backlog-mcp 1.0.1__tar.gz → 1.0.3__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 (25) hide show
  1. {backlog_mcp-1.0.1 → backlog_mcp-1.0.3}/.env.example +0 -1
  2. {backlog_mcp-1.0.1 → backlog_mcp-1.0.3}/PKG-INFO +3 -18
  3. {backlog_mcp-1.0.1 → backlog_mcp-1.0.3}/README.md +2 -17
  4. {backlog_mcp-1.0.1 → backlog_mcp-1.0.3}/app/server_settings.py +0 -3
  5. {backlog_mcp-1.0.1 → backlog_mcp-1.0.3}/app/tools/get_issue_details.py +1 -8
  6. backlog_mcp-1.0.3/app/tools/get_user_issue_list.py +28 -0
  7. {backlog_mcp-1.0.1 → backlog_mcp-1.0.3}/app/utils/ultils.py +27 -2
  8. {backlog_mcp-1.0.1 → backlog_mcp-1.0.3}/docs/mcp-installer-template.md +66 -78
  9. {backlog_mcp-1.0.1 → backlog_mcp-1.0.3}/pyproject.toml +1 -1
  10. {backlog_mcp-1.0.1 → backlog_mcp-1.0.3}/uv.lock +2 -2
  11. backlog_mcp-1.0.1/app/tools/get_user_issue_list.py +0 -70
  12. backlog_mcp-1.0.1/install-backlog-mcp.sh +0 -717
  13. {backlog_mcp-1.0.1 → backlog_mcp-1.0.3}/.gitignore +0 -0
  14. {backlog_mcp-1.0.1 → backlog_mcp-1.0.3}/.mise.toml +0 -0
  15. {backlog_mcp-1.0.1 → backlog_mcp-1.0.3}/app/__init__.py +0 -0
  16. {backlog_mcp-1.0.1 → backlog_mcp-1.0.3}/app/constants/__init__.py +0 -0
  17. {backlog_mcp-1.0.1 → backlog_mcp-1.0.3}/app/constants/constants.py +0 -0
  18. {backlog_mcp-1.0.1 → backlog_mcp-1.0.3}/app/core/__init__.py +0 -0
  19. {backlog_mcp-1.0.1 → backlog_mcp-1.0.3}/app/logging_config.py +0 -0
  20. {backlog_mcp-1.0.1 → backlog_mcp-1.0.3}/app/main.py +0 -0
  21. {backlog_mcp-1.0.1 → backlog_mcp-1.0.3}/app/models/__init__.py +0 -0
  22. {backlog_mcp-1.0.1 → backlog_mcp-1.0.3}/app/models/models.py +0 -0
  23. {backlog_mcp-1.0.1 → backlog_mcp-1.0.3}/app/tools/__init__.py +0 -0
  24. {backlog_mcp-1.0.1 → backlog_mcp-1.0.3}/app/utils/__init__.py +0 -0
  25. {backlog_mcp-1.0.1 → backlog_mcp-1.0.3}/app/utils/di.py +0 -0
@@ -1,4 +1,3 @@
1
1
  # Backlog API Settings
2
2
  BACKLOG_API_KEY=your_backlog_api_key_here
3
3
  BACKLOG_DOMAIN=your-space.backlog.com
4
- USER_ID=your_user_id
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: backlog-mcp
3
- Version: 1.0.1
3
+ Version: 1.0.3
4
4
  Summary: A Model Context Protocol (MCP) server for Backlog project management integration
5
5
  Author-email: BaoNguyen <baonguyen@teqnological.asia>
6
6
  Requires-Python: <3.14,>=3.13
@@ -55,22 +55,9 @@ Get detailed information about a Backlog issue by its issue key.
55
55
 
56
56
  ### `get_user_issue_list`
57
57
 
58
- Retrieve a filtered list of issues based on project, assignees, milestones, and other criteria.
58
+ Retrieve a list of issues assigned to the current user.
59
59
 
60
- **Parameters:**
61
- - `project_ids` (List[int], optional): List of project IDs.
62
- - `assignee_ids` (List[int], optional): List of assignee IDs (defaults to current user).
63
- - `status_ids` (List[int], optional): List of status IDs (defaults to non-closed).
64
- - `milestone_ids` (List[int], optional): List of milestone IDs.
65
- - `parent_issue_ids` (List[int], optional): List of parent issue IDs.
66
- - `created_since` (str, optional): Created since (YYYY-MM-DD).
67
- - `created_until` (str, optional): Created until (YYYY-MM-DD).
68
- - `updated_since` (str, optional): Updated since (YYYY-MM-DD).
69
- - `updated_until` (str, optional): Updated until (YYYY-MM-DD).
70
- - `start_date_since` (str, optional): Start Date since (YYYY-MM-DD).
71
- - `start_date_until` (str, optional): Start Date until (YYYY-MM-DD).
72
- - `due_date_since` (str, optional): Due Date since (YYYY-MM-DD).
73
- - `due_date_until` (str, optional): Due Date until (YYYY-MM-DD).
60
+ This tool automatically determines the current user's ID and returns only issues assigned to that user. No parameters are required.
74
61
 
75
62
  ## Running the Server Locally
76
63
 
@@ -89,13 +76,11 @@ Create a `.env` file in the root directory and add the following environment var
89
76
  # Backlog API Settings
90
77
  BACKLOG_API_KEY=your_backlog_api_key_here
91
78
  BACKLOG_DOMAIN=your-space.backlog.com
92
- USER_ID=your_user_id
93
79
  ```
94
80
 
95
81
  > **Important:**
96
82
  > - Replace `your_backlog_api_key_here` with your actual Backlog API key
97
83
  > - Replace `your-space.backlog.com` with your actual Backlog domain
98
- > - Replace `your_user_id` with your actual Backlog user ID
99
84
 
100
85
  ### 3. Start the server
101
86
 
@@ -39,22 +39,9 @@ Get detailed information about a Backlog issue by its issue key.
39
39
 
40
40
  ### `get_user_issue_list`
41
41
 
42
- Retrieve a filtered list of issues based on project, assignees, milestones, and other criteria.
42
+ Retrieve a list of issues assigned to the current user.
43
43
 
44
- **Parameters:**
45
- - `project_ids` (List[int], optional): List of project IDs.
46
- - `assignee_ids` (List[int], optional): List of assignee IDs (defaults to current user).
47
- - `status_ids` (List[int], optional): List of status IDs (defaults to non-closed).
48
- - `milestone_ids` (List[int], optional): List of milestone IDs.
49
- - `parent_issue_ids` (List[int], optional): List of parent issue IDs.
50
- - `created_since` (str, optional): Created since (YYYY-MM-DD).
51
- - `created_until` (str, optional): Created until (YYYY-MM-DD).
52
- - `updated_since` (str, optional): Updated since (YYYY-MM-DD).
53
- - `updated_until` (str, optional): Updated until (YYYY-MM-DD).
54
- - `start_date_since` (str, optional): Start Date since (YYYY-MM-DD).
55
- - `start_date_until` (str, optional): Start Date until (YYYY-MM-DD).
56
- - `due_date_since` (str, optional): Due Date since (YYYY-MM-DD).
57
- - `due_date_until` (str, optional): Due Date until (YYYY-MM-DD).
44
+ This tool automatically determines the current user's ID and returns only issues assigned to that user. No parameters are required.
58
45
 
59
46
  ## Running the Server Locally
60
47
 
@@ -73,13 +60,11 @@ Create a `.env` file in the root directory and add the following environment var
73
60
  # Backlog API Settings
74
61
  BACKLOG_API_KEY=your_backlog_api_key_here
75
62
  BACKLOG_DOMAIN=your-space.backlog.com
76
- USER_ID=your_user_id
77
63
  ```
78
64
 
79
65
  > **Important:**
80
66
  > - Replace `your_backlog_api_key_here` with your actual Backlog API key
81
67
  > - Replace `your-space.backlog.com` with your actual Backlog domain
82
- > - Replace `your_user_id` with your actual Backlog user ID
83
68
 
84
69
  ### 3. Start the server
85
70
 
@@ -13,7 +13,4 @@ class ServerSettings(BaseSettings):
13
13
  BACKLOG_API_KEY: str
14
14
  BACKLOG_DOMAIN: str # e.g., "your-space.backlog.com"
15
15
 
16
- # User Settings
17
- USER_ID: int
18
-
19
16
  settings = ServerSettings()
@@ -4,7 +4,6 @@ from app.utils.ultils import get_issue_detail_handler
4
4
 
5
5
  async def get_issue_details(
6
6
  issue_key: str,
7
- issue_title: str | None,
8
7
  timezone: str = "UTC"
9
8
  ):
10
9
  """
@@ -12,17 +11,11 @@ async def get_issue_details(
12
11
 
13
12
  Args:
14
13
  issue_key (str): The key of the Backlog issue to retrieve.
15
- issue_title (str): The title of the Backlog issue, used for logging or reference purposes.
16
14
  timezone (str, optional): The timezone to format datetime fields. Defaults to "UTC".
17
15
  """
18
16
  try:
19
- if not issue_key and not issue_title:
17
+ if not issue_key:
20
18
  raise ValueError("Please provide an issue key.")
21
- elif issue_title and not issue_key:
22
- raise ValueError(
23
- "Cannot retrieve task information with only the issue title. "
24
- "Please provide an issue key. Searching by title is not supported yet."
25
- )
26
19
  ctx = create_backlog_context()
27
20
  result = await get_issue_detail_handler(
28
21
  backlog_domain=ctx.backlog_domain,
@@ -0,0 +1,28 @@
1
+ from app.utils.di import create_backlog_context
2
+ from app.utils.ultils import get_user_task, get_current_user
3
+
4
+
5
+ async def get_user_issue_list():
6
+ """
7
+ Retrieves a list of issues assigned to the current user from Backlog.
8
+
9
+ This function automatically determines the current user's ID via API
10
+ and returns only issues assigned to that user.
11
+ """
12
+
13
+ try:
14
+ ctx = create_backlog_context()
15
+
16
+ # Fetch current user information
17
+ current_user = await get_current_user(ctx.backlog_domain, ctx.api_key)
18
+ current_user_id = current_user["id"]
19
+
20
+ # Get issues assigned to current user
21
+ issue_list = await get_user_task(
22
+ backlog_domain=ctx.backlog_domain,
23
+ api_key=ctx.api_key,
24
+ assignee_ids=[current_user_id]
25
+ )
26
+ return issue_list
27
+ except Exception as e:
28
+ raise e
@@ -46,8 +46,9 @@ def time_in_range(time: str, start_range: str, end_range: str):
46
46
  return start_range_time <= time_to_be_compared <= end_range_time
47
47
 
48
48
 
49
- def process_issue_detail(issue_detail, timezone):
49
+ def process_issue_detail(issue_detail, timezone, issue_key):
50
50
  processed_issue = {
51
+ "issue_key": issue_key,
51
52
  "summary": issue_detail["summary"],
52
53
  "description": issue_detail["description"]
53
54
  }
@@ -108,7 +109,7 @@ async def get_issue_detail_handler(
108
109
  comments_in_time_range.append(comment)
109
110
 
110
111
  issue_detail.update({"comments": comments_in_time_range})
111
- processed_detail = process_issue_detail(issue_detail, timezone)
112
+ processed_detail = process_issue_detail(issue_detail, timezone, issue_key)
112
113
  return processed_detail
113
114
 
114
115
  except Exception as e:
@@ -266,3 +267,27 @@ async def get_project_list(backlog_domain: str, api_key: str) -> list[int]:
266
267
  raise ValueError(f"Failed to get project list: {e}") from e
267
268
  except Exception as e:
268
269
  raise ValueError(f"Unexpected error while getting project list: {e}") from e
270
+
271
+
272
+ async def get_current_user(backlog_domain: str, api_key: str) -> dict:
273
+ """Get current user information from Backlog API.
274
+
275
+ Returns:
276
+ dict: {"id": int, "name": str}
277
+ """
278
+ url = f"{backlog_domain}api/v2/users/myself"
279
+ params = {"apiKey": api_key}
280
+
281
+ async with httpx.AsyncClient() as client:
282
+ try:
283
+ response = await client.get(url, params=params, timeout=10.0)
284
+ response.raise_for_status()
285
+ data = response.json()
286
+ return {
287
+ "id": data["id"],
288
+ "name": data["name"]
289
+ }
290
+ except httpx.HTTPError as e:
291
+ raise ValueError(f"Failed to get current user: {e}") from e
292
+ except Exception as e:
293
+ raise ValueError(f"Unexpected error while getting current user: {e}") from e
@@ -5,8 +5,9 @@
5
5
  This template allows LLMs to generate interactive installation scripts **exclusively for PyPI-published MCP servers**. The template file is typically placed in the repository of a PyPI project.
6
6
 
7
7
  **Important**:
8
- - This template is **PyPI-only**. It always uses the Standard Template Structure with `--index-url` and `--extra-index-url` arguments.
8
+ - This template is **PyPI-only** for production packages on pypi.org
9
9
  - MCP configuration JSONs from Cline, GitHub Copilot, or Claude Code do NOT include an `env` field by default. The LLM must ask the user about environment variables and how to handle them.
10
+ - **The MCP_NAME must match the PyPI package name exactly** for uvx to work correctly
10
11
 
11
12
  The generated script will:
12
13
 
@@ -75,7 +76,7 @@ The generated script will:
75
76
  - If **No**: Skip env var section entirely (script will have no env section)
76
77
 
77
78
  3. **Replace placeholders** in the template below with actual values based on user's answers:
78
- - `{{MCP_NAME}}` - The MCP server name (e.g., "backlog-mcp")
79
+ - `{{MCP_NAME}}` - The MCP server name (e.g., "backlog-mcp") - **must match PyPI package name**
79
80
  - `{{MCP_DISPLAY_NAME}}` - Human-readable name (e.g., "Backlog MCP")
80
81
  - `{{COMMAND}}` - The command (usually "uvx")
81
82
  - `{{ARGS}}` - Array of command arguments
@@ -87,15 +88,15 @@ The generated script will:
87
88
  - `{{TIMEOUT_VALUE}}` - Timeout value if present
88
89
  - `{{HAS_TYPE}}` - "true" or "false" based on config
89
90
 
90
- 3. **Generate the script** by replacing all placeholders with actual values
91
+ 4. **Generate the script** by replacing all placeholders with actual values
91
92
 
92
- 4. **Save as** `install-{{MCP_NAME}}.sh` and make it executable
93
+ 5. **Save as** `install-{{MCP_NAME}}.sh` and make it executable
93
94
 
94
95
  ---
95
96
 
96
97
  ## Standard Template Structure
97
98
 
98
- **IMPORTANT**: This template is for PyPI-published MCP servers only. You **MUST** always use the following canonical args structure. This ensures consistent installation across all PyPI-published MCP servers.
99
+ **IMPORTANT**: This template is for PyPI-published MCP servers only.
99
100
 
100
101
  ### Required Args Format
101
102
 
@@ -103,26 +104,24 @@ The `args` array **MUST** always follow this structure:
103
104
 
104
105
  ```json
105
106
  "args": [
106
- "--from",
107
- "{{PACKAGE_NAME}}@latest",
108
- "--index-url",
109
- "https://test.pypi.org/simple/",
110
- "--extra-index-url",
111
- "https://pypi.org/simple/",
112
- "{{MCP_NAME}}"
107
+ "{{MCP_NAME}}@latest"
113
108
  ]
114
109
  ```
115
110
 
116
- **Placeholders:**
117
- - `{{PACKAGE_NAME}}`: The PyPI package name (e.g., `backlog-mcp`)
118
- - `{{MCP_NAME}}`: The MCP server identifier (usually same as package name, e.g., `backlog-mcp`)
111
+ **Placeholder:**
112
+ - `{{MCP_NAME}}`: The MCP server identifier (e.g., `backlog-mcp`)
113
+ - **Critical**: `{{MCP_NAME}}` **must match the PyPI package name exactly** for uvx to install correctly
119
114
 
120
115
  **Conversion to bash script format:**
121
116
  ```bash
122
- "--from" "{{PACKAGE_NAME}}@latest" "--index-url" "https://test.pypi.org/simple/" "--extra-index-url" "https://pypi.org/simple/" "{{MCP_NAME}}" "ENV_START"
117
+ "{{MCP_NAME}}@latest" "ENV_START"
123
118
  ```
124
119
 
125
- **Note**: The `--index-url` and `--extra-index-url` arguments are **mandatory** and must always be included to ensure proper package resolution from both test.pypi.org and pypi.org.
120
+ **Note**: Production mode is simple because the package name usually matches the MCP name, and pypi.org is the default package index. The `ENV_START` marker separates args from environment variables.
121
+
122
+ **Examples:**
123
+ - If PyPI package name is `backlog-mcp` → MCP_NAME must be `backlog-mcp`
124
+ - If PyPI package name is `mcp-server-sqlite` → MCP_NAME must be `mcp-server-sqlite`
126
125
 
127
126
  ---
128
127
 
@@ -131,8 +130,9 @@ The `args` array **MUST** always follow this structure:
131
130
  **Important Notes:**
132
131
  1. Real MCP configurations from Cline/Copilot/Claude Code do NOT include an `env` field. The LLM must ask the user about environment variables separately.
133
132
  2. These examples show **reference configurations** that users might have. They are provided for reference only.
134
- 3. **Always use the Standard Template Structure** (see above) regardless of what the user's config shows. The user's config may be outdated, incomplete, or missing `--index-url`/`--extra-index-url` args.
135
- 4. The generated installer script will always include the complete Standard Template Structure with all required args.
133
+ 3. **Always use the Standard Template Structure** (see above) regardless of what the user's config shows.
134
+ 4. The generated installer script will always include the complete Standard Template Structure.
135
+ 5. **MCP_NAME must match the PyPI package name exactly**.
136
136
 
137
137
  **Cline config format (example - may vary):**
138
138
  ```json
@@ -144,18 +144,11 @@ The `args` array **MUST** always follow this structure:
144
144
  "type": "stdio",
145
145
  "command": "uvx",
146
146
  "args": [
147
- "--from",
148
- "backlog-mcp@latest",
149
- "--index-url",
150
- "https://test.pypi.org/simple/",
151
- "--extra-index-url",
152
- "https://pypi.org/simple/",
153
- "backlog-mcp"
147
+ "backlog-mcp@latest"
154
148
  ]
155
149
  }
156
150
  }
157
151
  ```
158
- *Note: This example shows the complete Standard Template Structure. User configs may be missing `--index-url` or `--extra-index-url` - always use Standard Template Structure for PyPI packages.*
159
152
 
160
153
  **GitHub Copilot config format (example - may vary):**
161
154
  ```json
@@ -165,18 +158,11 @@ The `args` array **MUST** always follow this structure:
165
158
  "timeout": 60000,
166
159
  "command": "uvx",
167
160
  "args": [
168
- "--from",
169
- "backlog-mcp@latest",
170
- "--index-url",
171
- "https://test.pypi.org/simple/",
172
- "--extra-index-url",
173
- "https://pypi.org/simple/",
174
- "backlog-mcp"
161
+ "backlog-mcp@latest"
175
162
  ]
176
163
  }
177
164
  }
178
165
  ```
179
- *Note: This example shows the complete Standard Template Structure. User configs may be missing `--index-url` or `--extra-index-url` - always use Standard Template Structure for PyPI packages.*
180
166
 
181
167
  **Claude Code config format (example - may vary):**
182
168
  ```json
@@ -184,27 +170,18 @@ The `args` array **MUST** always follow this structure:
184
170
  "backlog-mcp": {
185
171
  "command": "uvx",
186
172
  "args": [
187
- "--from",
188
- "backlog-mcp@latest",
189
- "--index-url",
190
- "https://test.pypi.org/simple/",
191
- "--extra-index-url",
192
- "https://pypi.org/simple/",
193
- "backlog-mcp"
173
+ "backlog-mcp@latest"
194
174
  ]
195
175
  }
196
176
  }
197
177
  ```
198
- *Note: This example shows the complete Standard Template Structure. User configs may be missing `--index-url` or `--extra-index-url` - always use Standard Template Structure for PyPI packages.*
199
178
 
200
179
  ### Example Output
201
180
 
202
181
  The generated script will:
203
182
  - Ask which agent (Cline/Copilot/Claude Code)
204
183
  - Check if "backlog-mcp" already exists
205
- - Prompt for BACKLOG_API_KEY (with default from config)
206
- - Prompt for BACKLOG_DOMAIN (with default from config)
207
- - Prompt for USER_ID (with default from config)
184
+ - Prompt for environment variables (if needed)
208
185
  - Write the configuration to the appropriate file
209
186
 
210
187
  ---
@@ -910,7 +887,7 @@ fi
910
887
 
911
888
  | Placeholder | Description | Example |
912
889
  |------------|-------------|---------|
913
- | `{{MCP_NAME}}` | The MCP server identifier (key in JSON) | `backlog-mcp` |
890
+ | `{{MCP_NAME}}` | The MCP server identifier (key in JSON) - **must match PyPI package name exactly** | `backlog-mcp` |
914
891
  | `{{MCP_DISPLAY_NAME}}` | Human-readable name for prompts (used in banner) | `Backlog MCP` |
915
892
  | `{{COMMAND}}` | Command to run | `uvx` |
916
893
  | `{{ARGS}}` | Array of command arguments | See example below |
@@ -932,10 +909,18 @@ Extract from the JSON key:
932
909
  }
933
910
  ```
934
911
 
912
+ **CRITICAL**: `{{MCP_NAME}}` **must match the PyPI package name exactly** for uvx to install correctly.
913
+
914
+ **Examples:**
915
+ - If PyPI package is `backlog-mcp` → `{{MCP_NAME}}` = `backlog-mcp`
916
+ - If PyPI package is `mcp-server-sqlite` → `{{MCP_NAME}}` = `mcp-server-sqlite`
917
+ - If PyPI package is `agent-coding-standards-mcp` → `{{MCP_NAME}}` = `agent-coding-standards-mcp`
918
+
935
919
  #### 2. `{{MCP_DISPLAY_NAME}}`
936
920
  Create a human-readable name:
937
921
  - `backlog-mcp` → `Backlog MCP`
938
922
  - `agent-coding-standards-mcp` → `Agent Coding Standards MCP`
923
+ - `mcp-server-sqlite` → `MCP Server SQLite`
939
924
 
940
925
  #### 3. `{{COMMAND}}`
941
926
  Usually `uvx`, but check the config:
@@ -945,24 +930,28 @@ Usually `uvx`, but check the config:
945
930
 
946
931
  #### 4. `{{ARGS}}`
947
932
 
948
- **ALWAYS use the Standard Template Structure** (see "Standard Template Structure" section above). This template is for PyPI packages only.
933
+ **Always use the Standard Template Structure:**
949
934
 
950
- Use this format:
951
935
  ```bash
952
- "--from" "{{PACKAGE_NAME}}@latest" "--index-url" "https://test.pypi.org/simple/" "--extra-index-url" "https://pypi.org/simple/" "{{MCP_NAME}}" "ENV_START"
936
+ "{{MCP_NAME}}@latest" "ENV_START"
953
937
  ```
954
938
 
955
939
  **Placeholders:**
956
- - Replace `{{PACKAGE_NAME}}` with the actual PyPI package name (e.g., `backlog-mcp`)
957
- - Replace `{{MCP_NAME}}` with the MCP server identifier (usually same as package name, e.g., `backlog-mcp`)
940
+ - Replace `{{MCP_NAME}}` with the MCP server identifier (e.g., `backlog-mcp`)
941
+ - **CRITICAL**: `{{MCP_NAME}}` must match the PyPI package name exactly
958
942
 
959
943
  **Important:**
960
944
  - Always append `"ENV_START"` as a marker after all args, before the env vars.
961
- - The `--index-url` and `--extra-index-url` arguments are **mandatory** and must always be included.
945
+ - The `ENV_START` marker is used by the Python script to separate args from env vars.
962
946
 
963
947
  **Example (backlog-mcp):**
964
948
  ```bash
965
- "--from" "backlog-mcp@latest" "--index-url" "https://test.pypi.org/simple/" "--extra-index-url" "https://pypi.org/simple/" "backlog-mcp" "ENV_START"
949
+ "backlog-mcp@latest" "ENV_START"
950
+ ```
951
+
952
+ **Example (mcp-server-sqlite):**
953
+ ```bash
954
+ "mcp-server-sqlite@latest" "ENV_START"
966
955
  ```
967
956
 
968
957
  #### 5. `{{ENV_VAR_SECTION}}` and `{{ENV_VAR_PROMPTS}}`
@@ -1088,7 +1077,7 @@ For Claude Code, always set:
1088
1077
 
1089
1078
  ## Complete Example: backlog-mcp
1090
1079
 
1091
- This example demonstrates generating an installer script for a PyPI-published MCP server (`backlog-mcp`). The generated script will always use the **Standard Template Structure** for args.
1080
+ This example demonstrates generating an installer script for a PyPI-published MCP server (`backlog-mcp`).
1092
1081
 
1093
1082
  ### Input Configuration
1094
1083
 
@@ -1103,29 +1092,23 @@ This example demonstrates generating an installer script for a PyPI-published MC
1103
1092
  "type": "stdio",
1104
1093
  "command": "uvx",
1105
1094
  "args": [
1106
- "--from",
1107
- "backlog-mcp@latest",
1108
- "--index-url",
1109
- "https://test.pypi.org/simple/",
1110
- "--extra-index-url",
1111
- "https://pypi.org/simple/",
1112
- "backlog-mcp"
1095
+ "backlog-mcp@latest"
1113
1096
  ]
1114
1097
  }
1115
1098
  }
1116
1099
  ```
1117
1100
 
1118
- **Note**: The generated installer script will always use the complete Standard Template Structure with all required args, regardless of what the user's config shows.
1101
+ **Important**: The MCP name (`backlog-mcp`) matches the PyPI package name (`backlog-mcp`). This is required for uvx to work correctly.
1119
1102
 
1120
1103
  The LLM must ask the user about environment variables separately.
1121
1104
 
1122
1105
  ### Generated Placeholder Values
1123
1106
 
1124
1107
  ```bash
1125
- MCP_NAME="backlog-mcp"
1108
+ MCP_NAME="backlog-mcp" # Must match PyPI package name
1126
1109
  MCP_DISPLAY_NAME="Backlog MCP"
1127
1110
  COMMAND="uvx"
1128
- ARGS="--from" "backlog-mcp@latest" "--index-url" "https://test.pypi.org/simple/" "--extra-index-url" "https://pypi.org/simple/" "backlog-mcp" "ENV_START"
1111
+ ARGS="backlog-mcp@latest" "ENV_START" # MCP_NAME matches package name
1129
1112
  HAS_AUTO_APPROVE="true"
1130
1113
  HAS_DISABLED="true"
1131
1114
  HAS_TIMEOUT="true"
@@ -1201,10 +1184,10 @@ echo ""
1201
1184
  **Using Standard Template Structure:**
1202
1185
 
1203
1186
  ```bash
1204
- "--from" "backlog-mcp@latest" "--index-url" "https://test.pypi.org/simple/" "--extra-index-url" "https://pypi.org/simple/" "backlog-mcp" "ENV_START"
1187
+ "backlog-mcp@latest" "ENV_START"
1205
1188
  ```
1206
1189
 
1207
- **Note**: This always uses the Standard Template Structure with all required args (`--index-url` and `--extra-index-url` are mandatory).
1190
+ **Note**: `backlog-mcp` matches the PyPI package name exactly.
1208
1191
 
1209
1192
  ### Generated ENV_VAR_VALUES
1210
1193
 
@@ -1226,7 +1209,8 @@ When generating a script from this template:
1226
1209
 
1227
1210
  - [ ] Parse the MCP config JSON (if provided) or use template structure
1228
1211
  - [ ] Extract MCP name from the key
1229
- - [ ] Extract command and args: Always use **Standard Template Structure** for args, include `--from`, `{{PACKAGE_NAME}}@latest`, `--index-url`, `--extra-index-url`, and `{{MCP_NAME}}`
1212
+ - [ ] **VERIFY**: MCP_NAME matches the PyPI package name exactly
1213
+ - [ ] Extract command and args: Always use **Standard Template Structure** for args
1230
1214
  - [ ] **ASK USER about env vars**: Does the MCP server need environment variables?
1231
1215
  - [ ] **For each env var needed**: Ask user if it's Fixed (cố định) or Variable (tùy biến)
1232
1216
  - If **Fixed**: Get value from user and hardcode in script
@@ -1242,30 +1226,34 @@ When generating a script from this template:
1242
1226
 
1243
1227
  ## Notes
1244
1228
 
1245
- 1. **Banner ASCII Art**: The banner is always the same ASCII art from `install-mcp.sh`. Only the `{{MCP_DISPLAY_NAME}}` changes in the banner.
1229
+ 1. **Package Name Matching**: **CRITICAL** - The `{{MCP_NAME}}` must match the PyPI package name exactly for uvx to install correctly. For example:
1230
+ - If PyPI package is `backlog-mcp` → MCP_NAME must be `backlog-mcp`
1231
+ - If PyPI package is `mcp-server-sqlite` → MCP_NAME must be `mcp-server-sqlite`
1232
+ - If PyPI package is `agent-coding-standards-mcp` → MCP_NAME must be `agent-coding-standards-mcp`
1246
1233
 
1247
- 2. **Sensitive Value Detection**: The template automatically detects sensitive values by checking if the env var name contains: `TOKEN`, `PASSWORD`, `KEY`, `SECRET`, or `API_KEY` (case-insensitive).
1234
+ 2. **Banner ASCII Art**: The banner is always the same ASCII art from `install-mcp.sh`. Only the `{{MCP_DISPLAY_NAME}}` changes in the banner.
1248
1235
 
1249
- 3. **Agent-Specific Behavior**:
1236
+ 3. **Sensitive Value Detection**: The template automatically detects sensitive values by checking if the env var name contains: `TOKEN`, `PASSWORD`, `KEY`, `SECRET`, or `API_KEY` (case-insensitive).
1237
+
1238
+ 4. **Agent-Specific Behavior**:
1250
1239
  - **Cline**: Supports all optional fields. Timeout uses **seconds** (e.g., `60` = 60 seconds)
1251
1240
  - **GitHub Copilot**: Doesn't support `autoApprove` or `disabled`. Timeout uses **milliseconds** (e.g., `60000` = 60 seconds). The Python script automatically converts seconds to milliseconds.
1252
1241
  - **Claude Code**: Doesn't support any optional fields (no timeout)
1253
1242
 
1254
- 4. **Workflow**: The template file is typically placed in a PyPI project repository (90% of use cases). When generating an installer script, the LLM should parse the config structure and ask the user about environment variables.
1243
+ 5. **Workflow**: The template file is typically placed in a PyPI project repository (90% of use cases). When generating an installer script, the LLM should parse the config structure and ask the user about environment variables.
1255
1244
 
1256
- 5. **Config Format**: MCP configurations from Cline, GitHub Copilot, or Claude Code do NOT include an `env` field by default. The LLM must ask the user about environment variables separately.
1245
+ 6. **Config Format**: MCP configurations from Cline, GitHub Copilot, or Claude Code do NOT include an `env` field by default. The LLM must ask the user about environment variables separately.
1257
1246
 
1258
- 6. **Environment Variables**: There are two types of env vars:
1247
+ 7. **Environment Variables**: There are two types of env vars:
1259
1248
  - **Fixed (Cố định)**: User provides the value when LLM asks → LLM hardcodes it into the script (no prompt in script). Use this for static values that don't change.
1260
1249
  - **Variable (Tùy biến)**: LLM generates prompt code in the script to ask user when running. Use this for values that vary per installation.
1261
1250
 
1262
- 7. **Error Handling**: The script includes comprehensive error handling for:
1251
+ 8. **Error Handling**: The script includes comprehensive error handling for:
1263
1252
  - Missing system requirements
1264
1253
  - Invalid JSON in config files
1265
1254
  - Existing MCP configurations
1266
1255
  - Missing environment variables
1267
1256
 
1268
- 8. **JSON Comments**: The script handles JSON files with comments (both `//` and `/* */` style) by stripping them before parsing.
1269
-
1270
- 9. **Important Bug Fix**: The `strip_json_comments` function uses `enumerate(lines)` instead of `lines.index(line)` to get the current line index. This prevents the `"'...' is not in list"` error that occurs when a modified line (after stripping comments) cannot be found in the original list. Always use `line_idx` from `enumerate()` when accessing `lines[line_idx+1:]` to check for trailing commas.
1257
+ 9. **JSON Comments**: The script handles JSON files with comments (both `//` and `/* */` style) by stripping them before parsing.
1271
1258
 
1259
+ 10. **Important Bug Fix**: The `strip_json_comments` function uses `enumerate(lines)` instead of `lines.index(line)` to get the current line index. This prevents the `"'...' is not in list"` error that occurs when a modified line (after stripping comments) cannot be found in the original list. Always use `line_idx` from `enumerate()` when accessing `lines[line_idx+1:]` to check for trailing commas.
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "backlog-mcp"
3
- version = "1.0.1"
3
+ version = "1.0.3"
4
4
  description = "A Model Context Protocol (MCP) server for Backlog project management integration"
5
5
  authors = [{name = "BaoNguyen", email = "baonguyen@teqnological.asia"}]
6
6
  readme = "README.md"
@@ -1,5 +1,5 @@
1
1
  version = 1
2
- revision = 2
2
+ revision = 3
3
3
  requires-python = "==3.13.*"
4
4
 
5
5
  [[package]]
@@ -34,7 +34,7 @@ wheels = [
34
34
 
35
35
  [[package]]
36
36
  name = "backlog-mcp"
37
- version = "0.0.10"
37
+ version = "1.0.2"
38
38
  source = { editable = "." }
39
39
  dependencies = [
40
40
  { name = "httpx" },
@@ -1,70 +0,0 @@
1
- from app.utils.di import create_backlog_context
2
- from app.utils.ultils import get_user_task
3
-
4
- from app.server_settings import settings
5
-
6
-
7
- async def get_user_issue_list(
8
- project_ids: list[int] | None = None,
9
- assignee_ids: list[int] | None = None,
10
- status_ids: list[int] | None = None,
11
- milestone_ids: list[int] | None = None,
12
- parent_issue_ids: list[int] | None = None,
13
- created_since: str | None = None,
14
- created_until: str | None = None,
15
- updated_since: str | None = None,
16
- updated_until: str | None = None,
17
- start_date_since: str | None = None,
18
- start_date_until: str | None = None,
19
- due_date_since: str | None = None,
20
- due_date_until: str | None = None,
21
- ):
22
- """
23
- Retrieves a filtered list of issues from Backlog for the users.
24
-
25
- Args:
26
- project_ids (list[int], optional): List of project IDs to filter issues.
27
- assignee_ids (list[int], optional): List of assignee IDs to filter issues (defaults to current user).
28
- status_ids (list[int], optional): List of status IDs to filter issues (defaults to all non-closed statuses).
29
- milestone_ids (list[int], optional): List of milestone IDs to filter issues.
30
- parent_issue_ids (list[int], optional): List of parent issue IDs to filter issues.
31
-
32
- created_since (str, optional): Created since (YYYY-MM-DD).
33
- created_until (str, optional): Created until (YYYY-MM-DD).
34
-
35
- updated_since (str, optional): Updated since (YYYY-MM-DD).
36
- updated_until (str, optional): Updated until (YYYY-MM-DD).
37
-
38
- start_date_since (str, optional): Start Date since (YYYY-MM-DD).
39
- start_date_until (str, optional): Start Date until (YYYY-MM-DD).
40
-
41
- due_date_since (str, optional): Due Date since (YYYY-MM-DD).
42
- due_date_until (str, optional): Due Date until (YYYY-MM-DD).
43
- """
44
-
45
- try:
46
- ctx = create_backlog_context()
47
-
48
- if assignee_ids is None:
49
- assignee_ids = [settings.USER_ID]
50
-
51
- issue_list = await get_user_task(
52
- backlog_domain=ctx.backlog_domain,
53
- api_key=ctx.api_key,
54
- project_ids=project_ids,
55
- assignee_ids=assignee_ids,
56
- status_ids=status_ids,
57
- milestone_ids=milestone_ids,
58
- parent_issue_ids=parent_issue_ids,
59
- created_since=created_since,
60
- created_until=created_until,
61
- updated_since=updated_since,
62
- updated_until=updated_until,
63
- start_date_since=start_date_since,
64
- start_date_until=start_date_until,
65
- due_date_since=due_date_since,
66
- due_date_until=due_date_until
67
- )
68
- return issue_list
69
- except Exception as e:
70
- raise e