Skip to content

feat(tapd): accept local image paths in image_url and auto-upload to TAPD image hosting - #14

Open
RaphLorr wants to merge 1 commit into
TencentCloudCommunity:mainfrom
RaphLorr:feat/tapd-native-image-upload
Open

feat(tapd): accept local image paths in image_url and auto-upload to TAPD image hosting#14
RaphLorr wants to merge 1 commit into
TencentCloudCommunity:mainfrom
RaphLorr:feat/tapd-native-image-upload

Conversation

@RaphLorr

@RaphLorr RaphLorr commented Aug 9, 2026

Copy link
Copy Markdown
Contributor

Summary

  • image_url / image_urls / media previously required an already-public URL, so embedding a local screenshot meant standing up an external image host (e.g. an object-storage bucket with public read). That pushes screenshots outside the workspace's own permission model.
  • These parameters now also accept an absolute path to a local image file. The file is uploaded to TAPD's own image hosting via POST /files/upload_image, and the returned image_src is embedded instead.
  • Public URLs and paths already under /tfl/ are passed through untouched, so this is backward compatible.

Changes

  • tapd.py: new TAPDClient.upload_image(). It uses multipart/form-data and cannot reuse _make_request(), which sends json= and pins Content-Type: application/json — that header prevents requests from generating a multipart boundary, so it is explicitly dropped here.
  • server.py: _is_local_image_path() and _upload_local_images(), hooked into _render_rich_description(). All six write tools inherit the behaviour: create_story_or_task, update_story_or_task, create_bug, update_bug, create_comments, update_comments.
  • server.py: a standalone upload_image tool, for callers that want the image path / HTML snippet before composing the description themselves.
  • Docstrings of the five tools that document media parameters now state that a local absolute path is accepted, since the docstring is the only description the model sees.

Behaviour notes

  • Limits follow the API: 5MB per image, PNG/GIF/JPG/JPEG/BMP, one image per call.
  • Requires the MCP server to run on the same machine as the image file. This always holds in stdio mode; the docstring calls it out for streamable-http deployments.
  • Upload failures raise rather than degrading to a broken <img>. A ticket created with its screenshot silently missing is worse than a failed call the caller can see and retry.
  • Video handling is unchanged: TAPD has no video upload endpoint, so video_url / video_urls still require an externally reachable URL.

Test plan

  • Unit tests for path detection and upload/replace logic: public URL passthrough, /tfl/ paths not re-uploaded, video items skipped, missing workspace_id passthrough, upload failure raises, missing image_src raises, oversize raises, uppercase extensions accepted
  • End-to-end against a real workspace: create_bug with image_url set to a local absolute path produced <img src="/tfl/pictures/202608/api_*.png" ... /> in the description; verified by reading the bug back through the API
  • Confirmed POST /files/upload_image works on api.tapd.cn (the documentation page describes it on a different host)
  • Verify tool descriptions render correctly via MCP inspector

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant