<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Germey</title>
    <description>The latest articles on DEV Community by Germey (@germey).</description>
    <link>https://dev.to/germey</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3834065%2F818e1a39-4e87-4a5b-b466-f76b66eb7301.png</url>
      <title>DEV Community: Germey</title>
      <link>https://dev.to/germey</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/germey"/>
    <language>en</language>
    <item>
      <title>How to Use NanoBanana MCP in Cursor for Practical Image Editing Workflows</title>
      <dc:creator>Germey</dc:creator>
      <pubDate>Fri, 02 Oct 2026 01:05:13 +0000</pubDate>
      <link>https://dev.to/germey/how-to-use-nanobanana-mcp-in-cursor-for-practical-image-editing-workflows-3fdc</link>
      <guid>https://dev.to/germey/how-to-use-nanobanana-mcp-in-cursor-for-practical-image-editing-workflows-3fdc</guid>
      <description>&lt;p&gt;Long URLs are easy to copy once and surprisingly annoying to manage when a release, newsletter, or launch note contains five of them; this guide shows how to let Codex CLI shorten them without leaving the terminal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcm5g7z04o4ya5pieimh9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcm5g7z04o4ya5pieimh9.png" alt="Codex CLI and ShortURL MCP workflow" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What you are building
&lt;/h2&gt;

&lt;p&gt;The setup is deliberately small: Codex CLI acts as the client, a hosted ShortURL MCP server exposes one tool, and your instruction in the terminal becomes a tool call.&lt;/p&gt;

&lt;p&gt;The MCP server documented by Ace Data Cloud is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://shorturl.mcp.acedata.cloud/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It exposes a single tool named &lt;code&gt;shorturl_create&lt;/code&gt;. That tool handles both individual links and batches, so you do not need separate integrations for a one-off URL and a list of release-note links.&lt;/p&gt;

&lt;p&gt;This is a useful first MCP project because the behavior is easy to verify. You provide one or more long URLs, Codex calls the tool, and you inspect the shortened results. There is no complicated agent state, database, or local service to maintain.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure the MCP server in Codex CLI
&lt;/h2&gt;

&lt;p&gt;Codex reads MCP server definitions from &lt;code&gt;~/.codex/config.toml&lt;/code&gt;. Open that file in your editor and add the following block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[mcp_servers.shorturl]&lt;/span&gt;
&lt;span class="py"&gt;url&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"https://shorturl.mcp.acedata.cloud/mcp"&lt;/span&gt;
&lt;span class="py"&gt;type&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"http"&lt;/span&gt;

&lt;span class="py"&gt;http_headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="py"&gt;"Authorization"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Bearer yourToken"&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replace &lt;code&gt;yourToken&lt;/code&gt; with your Ace Data Cloud API token. Keep the &lt;code&gt;Bearer&lt;/code&gt; prefix and the space after it: the full value is sent through the &lt;code&gt;Authorization&lt;/code&gt; header when Codex connects to the remote MCP server.&lt;/p&gt;

&lt;p&gt;A few details are worth noticing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;shorturl&lt;/code&gt; is the local name of the MCP server inside Codex. It is descriptive, but it is not the remote tool name.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;url&lt;/code&gt; points to the hosted MCP endpoint.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;type = "http"&lt;/code&gt; tells Codex that this is a remote HTTP MCP server.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;http_headers&lt;/code&gt; carries authentication without putting the token into every prompt.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Save the file, then restart your Codex session. The documentation states that the tool is loaded on the next startup, so changing the TOML while a session is already running may not make it immediately available.&lt;/p&gt;

&lt;p&gt;Treat the token like any other credential. Do not paste the completed configuration into an issue, commit it to a dotfiles repository, or include it in a screenshot.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with one link
&lt;/h2&gt;

&lt;p&gt;For the first test, use a direct instruction that makes the desired tool obvious:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Shorten this link: https://platform.acedata.cloud
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Codex should recognize that the request matches the ShortURL capability and call &lt;code&gt;shorturl_create&lt;/code&gt;. Starting with one URL helps separate connection problems from batch-input problems.&lt;/p&gt;

&lt;p&gt;If nothing happens, check the basics in this order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Confirm that the TOML block is in &lt;code&gt;~/.codex/config.toml&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Confirm the URL is exactly &lt;code&gt;https://shorturl.mcp.acedata.cloud/mcp&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Check that the authorization value begins with &lt;code&gt;Bearer&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Restart Codex after saving the file.&lt;/li&gt;
&lt;li&gt;Make the prompt explicit by using the verb “shorten.”&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That last point matters in agent workflows. “Prepare this link for sharing” leaves room for interpretation, while “Shorten this link” maps directly to the available tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  Turn it into a batch workflow
&lt;/h2&gt;

&lt;p&gt;The more practical use case is shortening several links at once. For example, after preparing release notes, you can give Codex a compact task like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Shorten these links for a release email:
- https://example.com/releases/2.4.0
- https://example.com/docs/migration-guide
- https://example.com/changelog

Return a Markdown list that keeps each original label next to its short URL.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The documented ShortURL MCP supports batch creation, while Codex can take care of the surrounding formatting. This division of labor is useful: the MCP tool performs the external action, and the model turns the returned values into the shape your workflow needs.&lt;/p&gt;

&lt;p&gt;You can use the same pattern for launch checklists, support replies, event resources, or a set of links collected during research. Ask for the final format you actually need—Markdown, a plain-text email section, or a checklist—but keep the URL-shortening action explicit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the workflow predictable
&lt;/h2&gt;

&lt;p&gt;Tool-enabled terminal workflows are most reliable when the instruction has three parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Action:&lt;/strong&gt; shorten the links.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Input:&lt;/strong&gt; provide the exact URLs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Output contract:&lt;/strong&gt; specify how the results should be organized.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Shorten the five URLs below. Preserve their order, do not rewrite the titles,
and return a two-column Markdown table with Title and Short URL.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This does not add hidden capabilities to &lt;code&gt;shorturl_create&lt;/code&gt;; it simply gives Codex a clear way to present the tool's output. If a URL is malformed, fix the source input instead of asking the agent to guess what you intended.&lt;/p&gt;

&lt;p&gt;I like this integration as a first MCP exercise because it solves a real, boring problem with very little machinery: one config block, one remote tool, and a result you can verify immediately. The exact setup and current examples are available in the &lt;a href="https://platform.acedata.cloud/documents/codex-mcp-short-url" rel="noopener noreferrer"&gt;Codex with ShortURL MCP documentation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devtools</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
    <item>
      <title>How to Generate and Edit Images from Claude Code with Flux MCP</title>
      <dc:creator>Germey</dc:creator>
      <pubDate>Thu, 01 Oct 2026 01:09:00 +0000</pubDate>
      <link>https://dev.to/germey/how-to-generate-and-edit-images-from-claude-code-with-flux-mcp-1hl3</link>
      <guid>https://dev.to/germey/how-to-generate-and-edit-images-from-claude-code-with-flux-mcp-1hl3</guid>
      <description>&lt;p&gt;A lot of developer work needs small but polished visuals: a cover for a technical post, an illustration for a docs page, or a corrected poster where only one detail changed. The annoying part is that image work often pulls you out of the terminal, even when the rest of the task is already happening in Claude Code.&lt;/p&gt;

&lt;p&gt;Flux MCP is a practical way to keep that visual step inside the same coding workflow. You configure one MCP server, verify it once, and then ask Claude Code to generate or edit images with natural language.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you can do
&lt;/h2&gt;

&lt;p&gt;The Flux MCP setup documented by Ace Data Cloud gives Claude Code two image tools:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;flux_generate_image&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Text-to-image generation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;flux_edit_image&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Image editing&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The same document describes three Flux model directions you can use from Claude Code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Dev&lt;/strong&gt;: fast draft-level exploration when you are not sure about the style yet;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pro&lt;/strong&gt;: more detailed image generation after you pick a direction;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kontext&lt;/strong&gt;: editing an existing image without regenerating the whole thing.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That maps well to real builder work. You can quickly try a few blog-cover directions, choose one, regenerate it with more detail, and later fix a small piece of text or layout in an existing image.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;Flux MCP is added to Claude Code as an HTTP transport server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://flux.mcp.acedata.cloud/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Authentication is passed through a header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Authorization: Bearer YOUR_ACEDATACLOUD_API_KEY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A local project setup looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add flux &lt;span class="nt"&gt;--transport&lt;/span&gt; http https://flux.mcp.acedata.cloud/mcp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer YOUR_ACEDATACLOUD_API_KEY"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nb"&gt;local&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the uppercase &lt;code&gt;-H&lt;/code&gt;. In Claude Code, lowercase &lt;code&gt;-h&lt;/code&gt; means help, so a tiny flag typo can make the command behave very differently from what you intended.&lt;/p&gt;

&lt;p&gt;The documented scopes are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;local&lt;/code&gt;: bound to the current project directory;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;user&lt;/code&gt;: visible across projects on your machine;&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;project&lt;/code&gt;: written into &lt;code&gt;.mcp.json&lt;/code&gt; for the current project.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For most experiments, I would start with &lt;code&gt;local&lt;/code&gt;. It gives you a low-risk way to test the workflow in one repository before deciding whether it belongs in your global Claude Code setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Add Flux MCP to Claude Code
&lt;/h2&gt;

&lt;p&gt;From the project where you want to use image generation, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add flux &lt;span class="nt"&gt;--transport&lt;/span&gt; http https://flux.mcp.acedata.cloud/mcp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer YOUR_ACEDATACLOUD_API_KEY"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nb"&gt;local&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you expect to use Flux across many projects, switch only the scope:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add flux &lt;span class="nt"&gt;--transport&lt;/span&gt; http https://flux.mcp.acedata.cloud/mcp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer YOUR_ACEDATACLOUD_API_KEY"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-s&lt;/span&gt; user
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a team project, you can use project scope:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add flux &lt;span class="nt"&gt;--transport&lt;/span&gt; http https://flux.mcp.acedata.cloud/mcp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer YOUR_ACEDATACLOUD_API_KEY"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-s&lt;/span&gt; project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Be careful with that last option. Project scope writes configuration into &lt;code&gt;.mcp.json&lt;/code&gt; in the project root. The config may be useful for a private team repo, but the real token should not be committed to public repositories, issues, screenshots, or chat logs. Use placeholders or have each person add their own token locally.&lt;/p&gt;

&lt;p&gt;When Claude Code reads a project-level config for the first time, it may show &lt;code&gt;Pending approval&lt;/code&gt;. That is a normal trust prompt, not necessarily a Flux problem.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Verify the MCP connection
&lt;/h2&gt;

&lt;p&gt;Before asking for images, check the server status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You want &lt;code&gt;flux&lt;/code&gt; to show &lt;code&gt;✓ Connected&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If it fails, check the three most boring things first:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;the token after &lt;code&gt;Authorization: Bearer&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;the exact server URL, including &lt;code&gt;/mcp&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;the scope you used when adding the server.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is faster than debugging prompts or assuming a model issue. If the MCP handshake is not connected, Claude Code cannot call the tools reliably.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Draft image directions with Flux Dev
&lt;/h2&gt;

&lt;p&gt;When the visual direction is unclear, start with fast drafts. The source document gives this example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Use flux-dev to quickly generate 3 different styles of developer blog cover images, trying flat, realistic, and abstract styles
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is a good pattern because it asks for comparison, not perfection. In a real docs workflow, I would add context from the file I am editing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Use flux-dev to generate 3 cover directions for this tutorial page. Keep the style technical, dark, and minimal. Try flat, realistic, and abstract variants.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once you see the directions, pick the strongest one instead of trying to force the first image to be perfect.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Refine with Flux Pro
&lt;/h2&gt;

&lt;p&gt;After a draft works, regenerate the chosen direction with more detail. The documented example is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Use flux-pro to regenerate the second image, increasing details and resolution
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This two-step approach is useful because it separates taste decisions from final rendering. You do not spend effort polishing an image direction that might be wrong for the post, README, or landing page.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 5: Fix existing images with Kontext editing
&lt;/h2&gt;

&lt;p&gt;Flux MCP is not only for new images. The documented &lt;code&gt;flux_edit_image&lt;/code&gt; workflow supports local edits to an existing image. The example is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Edit this poster image, changing the date in the bottom right corner from 2024 to 2025
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For developer content, this can be more useful than full regeneration. You might need to update a date, remove stale text, or adjust a small visual detail without changing the whole composition.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical workflow for technical content
&lt;/h2&gt;

&lt;p&gt;Here is the workflow I would use for a real tutorial or release note:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ask Claude Code to read the Markdown or page that needs an image.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;flux_generate_image&lt;/code&gt; with Dev-style exploration for 2–3 directions.&lt;/li&gt;
&lt;li&gt;Pick one direction and ask for a Pro-style refinement.&lt;/li&gt;
&lt;li&gt;If something small is wrong later, use &lt;code&gt;flux_edit_image&lt;/code&gt; instead of starting over.&lt;/li&gt;
&lt;li&gt;Save the final image URL or asset reference back into the Markdown.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The value is not that every visual becomes automatic. The value is that the image task stays close to the code, copy, and context that created the need for the image in the first place.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final notes
&lt;/h2&gt;

&lt;p&gt;Start with &lt;code&gt;local&lt;/code&gt;, verify with &lt;code&gt;claude mcp list&lt;/code&gt;, and keep tokens private. Use Dev for exploration, Pro for the final version, and Kontext when an existing image only needs a targeted edit.&lt;/p&gt;

&lt;p&gt;The full setup notes are in the &lt;a href="https://platform.acedata.cloud/documents/claude-code-mcp-flux" rel="noopener noreferrer"&gt;official Ace Data Cloud Flux MCP document&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devtools</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
    <item>
      <title>A Practical Guide to Building with the Kimi K3 Chat Completions API</title>
      <dc:creator>Germey</dc:creator>
      <pubDate>Wed, 30 Sep 2026 01:05:01 +0000</pubDate>
      <link>https://dev.to/germey/a-practical-guide-to-building-with-the-kimi-k3-chat-completions-api-58pb</link>
      <guid>https://dev.to/germey/a-practical-guide-to-building-with-the-kimi-k3-chat-completions-api-58pb</guid>
      <description>&lt;p&gt;Reasoning models are useful only when your application can call them predictably, stream partial output, and preserve enough conversation state for follow-up turns.&lt;/p&gt;

&lt;p&gt;This guide walks through a small, practical Kimi K3 chat-completion workflow using Ace Data Cloud's Kimi endpoint. We will cover the request shape, the response fields you should actually read, how to enable streaming, and how to pass multi-turn messages without inventing a custom protocol.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you can do
&lt;/h2&gt;

&lt;p&gt;The Kimi Chat Completion API lets you call the &lt;code&gt;kimi-k3&lt;/code&gt; model through an HTTP API. The documented use cases include ordinary chat completion, streaming responses, multi-turn dialogue, and K3 reasoning intensity control through &lt;code&gt;reasoning_effort&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The important request fields are:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;model&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Selects the Kimi model. The guide recommends &lt;code&gt;kimi-k3&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;messages&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;An array of dialogue messages. Each item has &lt;code&gt;role&lt;/code&gt; and &lt;code&gt;content&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;role&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Supports &lt;code&gt;user&lt;/code&gt;, &lt;code&gt;assistant&lt;/code&gt;, &lt;code&gt;system&lt;/code&gt;, and &lt;code&gt;tool&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;reasoning_effort&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Top-level field for K3 reasoning. The supported value is &lt;code&gt;max&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;stream&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Set to &lt;code&gt;true&lt;/code&gt; when you want line-by-line streaming output.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The endpoint used throughout the guide is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST https://api.acedata.cloud/kimi/chat/completions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Authentication is sent with a bearer token:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Authorization: Bearer $ACEDATACLOUD_API_KEY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;At the simplest level, you send a JSON body containing the model and a &lt;code&gt;messages&lt;/code&gt; array. Kimi returns a Chat Completions-style response with an &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;model&lt;/code&gt;, &lt;code&gt;choices&lt;/code&gt;, and &lt;code&gt;usage&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is a minimal request that asks Kimi K3 to review code and provide a fix:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl https://api.acedata.cloud/kimi/chat/completions &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer &lt;/span&gt;&lt;span class="nv"&gt;$ACEDATACLOUD_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "model": "kimi-k3",
    "messages": [
      {"role": "user", "content": "Review this code and provide a fix"}
    ],
    "reasoning_effort": "max"
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A normal response contains a &lt;code&gt;choices&lt;/code&gt; array. The assistant reply is in &lt;code&gt;choices[0].message.content&lt;/code&gt;. The &lt;code&gt;usage&lt;/code&gt; object reports token counts, including &lt;code&gt;prompt_tokens&lt;/code&gt;, &lt;code&gt;completion_tokens&lt;/code&gt;, and &lt;code&gt;total_tokens&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A shortened response looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"msg_2D4Btbg1WgvkNE3tCYkR4xGA"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"object"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"chat.completion"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"kimi-k3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"choices"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"index"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"assistant"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello! How can I help you today?"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"finish_reason"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"stop"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"usage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"prompt_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;86&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"completion_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;206&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"total_tokens"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;292&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a first integration, store the returned &lt;code&gt;id&lt;/code&gt; for observability, read &lt;code&gt;choices[0].message&lt;/code&gt;, and log &lt;code&gt;usage&lt;/code&gt; so you can understand how prompts grow over time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use &lt;code&gt;reasoning_effort&lt;/code&gt; carefully
&lt;/h2&gt;

&lt;p&gt;For &lt;code&gt;kimi-k3&lt;/code&gt;, reasoning is always enabled. The documented top-level request field is &lt;code&gt;reasoning_effort&lt;/code&gt;, and the supported value is currently &lt;code&gt;max&lt;/code&gt;. If you omit the field, the behavior is also &lt;code&gt;max&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That means you should not build application logic that depends on unsupported strings such as &lt;code&gt;standard&lt;/code&gt; or &lt;code&gt;high&lt;/code&gt;. They may be partially accepted by upstream compatibility layers, but the guide explicitly says not to rely on them changing reasoning behavior.&lt;/p&gt;

&lt;p&gt;In Python with an OpenAI-style client, the field can be passed directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;completions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kimi-k3&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;messages&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Design a reliable task queue&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="n"&gt;reasoning_effort&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;max&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For multi-turn dialogues and tool calls, return the complete assistant message from the previous round back into &lt;code&gt;messages&lt;/code&gt;, including fields such as &lt;code&gt;reasoning_content&lt;/code&gt; and &lt;code&gt;tool_calls&lt;/code&gt; when they are present. This keeps the next request faithful to what the model actually produced.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add streaming for better UX
&lt;/h2&gt;

&lt;p&gt;For a web app or terminal assistant, waiting for the entire response can feel slow. The API supports streaming with &lt;code&gt;stream: true&lt;/code&gt; in the JSON body.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.acedata.cloud/kimi/chat/completions&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;accept&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer {token}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content-type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;kimi-k3&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;messages&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;role&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Hello&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}],&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;reasoning_effort&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;max&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;stream&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The streaming response arrives as multiple &lt;code&gt;data:&lt;/code&gt; blocks. During the stream, new content appears inside &lt;code&gt;choices[].delta&lt;/code&gt;. K3 may stream &lt;code&gt;reasoning_content&lt;/code&gt; as well as final &lt;code&gt;content&lt;/code&gt;. The stream is complete when the data value is &lt;code&gt;[DONE]&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In a UI, treat these chunks as events: append &lt;code&gt;delta.content&lt;/code&gt; to the visible answer, optionally handle &lt;code&gt;delta.reasoning_content&lt;/code&gt; separately, and stop reading when you receive &lt;code&gt;[DONE]&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep multi-turn chat simple
&lt;/h2&gt;

&lt;p&gt;You do not need a special session object for a basic multi-turn chat. Send previous turns in the &lt;code&gt;messages&lt;/code&gt; array:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"kimi-k3"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"messages"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"assistant"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello! How can I help you today?"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;"role"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"user"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"What model are you?"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"reasoning_effort"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"max"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The response shape remains the same: inspect &lt;code&gt;choices&lt;/code&gt;, read the assistant message, and track &lt;code&gt;usage&lt;/code&gt;. As your conversation gets longer, this is also where token usage becomes important. Logging &lt;code&gt;usage.total_tokens&lt;/code&gt; early will save you debugging time later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handle errors before users see them
&lt;/h2&gt;

&lt;p&gt;The guide documents several error categories worth mapping into clear application messages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;400 token_mismatched&lt;/code&gt;: bad request, possibly missing or invalid parameters.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;400 api_not_implemented&lt;/code&gt;: bad request, possibly missing or invalid parameters.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;401 invalid_token&lt;/code&gt;: invalid or missing authorization token.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;429 too_many_requests&lt;/code&gt;: rate limit exceeded.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;500 api_error&lt;/code&gt;: server-side failure.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A typical error response includes &lt;code&gt;success: false&lt;/code&gt;, an &lt;code&gt;error&lt;/code&gt; object with &lt;code&gt;code&lt;/code&gt; and &lt;code&gt;message&lt;/code&gt;, and a &lt;code&gt;trace_id&lt;/code&gt;. Log the &lt;code&gt;trace_id&lt;/code&gt;; it is the field you will want when investigating a failed request.&lt;/p&gt;

&lt;h2&gt;
  
  
  A good first build
&lt;/h2&gt;

&lt;p&gt;If I were adding Kimi K3 to an app, I would start with one non-streaming endpoint, log &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;usage&lt;/code&gt;, then add streaming only after the basic response parser is stable. After that, I would add multi-turn history and make sure the full previous assistant message is preserved.&lt;/p&gt;

&lt;p&gt;That order keeps the integration boring: request shape first, response parsing second, streaming third, conversation memory last.&lt;/p&gt;

&lt;p&gt;For the original field reference and examples, see the Ace Data Cloud Kimi Chat Completion API guide: &lt;a href="https://platform.acedata.cloud/documents/kimi-chat-completion-integration" rel="noopener noreferrer"&gt;https://platform.acedata.cloud/documents/kimi-chat-completion-integration&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
    <item>
      <title>A Practical Guide to Configuring Claude Desktop with a Third-Party Inference Gateway</title>
      <dc:creator>Germey</dc:creator>
      <pubDate>Mon, 28 Sep 2026 01:08:30 +0000</pubDate>
      <link>https://dev.to/germey/a-practical-guide-to-configuring-claude-desktop-with-a-third-party-inference-gateway-4bea</link>
      <guid>https://dev.to/germey/a-practical-guide-to-configuring-claude-desktop-with-a-third-party-inference-gateway-4bea</guid>
      <description>&lt;p&gt;If you use Claude Desktop as a daily coding or research companion, a third-party inference gateway gives you a cleaner way to route model calls while keeping the desktop workflow familiar.&lt;/p&gt;

&lt;p&gt;This guide focuses on one specific setup: configuring Claude Desktop’s &lt;strong&gt;Third-Party Inference Gateway&lt;/strong&gt; with Ace Data Cloud. This is not the Claude Code setup, and it is not the MCP Connector configuration inside Claude Desktop. The goal here is narrower: set the gateway fields correctly, restart the app, and verify that Claude Desktop can call models, stream messages, and continue tool calls through the gateway.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you are configuring
&lt;/h2&gt;

&lt;p&gt;Claude Desktop exposes a developer-mode menu for third-party inference. In that screen, you choose &lt;strong&gt;Gateway&lt;/strong&gt; and provide a base URL, an API key, and an auth scheme.&lt;/p&gt;

&lt;p&gt;The values from the Ace Data Cloud guide are:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Claude Desktop field&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Gateway base URL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://api.acedata.cloud&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Gateway API key&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;your Ace Data Cloud API key&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Gateway auth scheme&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;bearer&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Credential kind&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Static API key&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Under the hood, the gateway supports &lt;code&gt;/v1/models&lt;/code&gt;, Bearer-authenticated streaming &lt;code&gt;/v1/messages&lt;/code&gt;, tool calling, and &lt;code&gt;tool_result&lt;/code&gt; continuation used by Claude Desktop.&lt;/p&gt;

&lt;p&gt;That matters because a simple chat completion is not enough for a desktop assistant. If your workflow uses tools, Claude Desktop needs to send tool calls, receive results, and continue the conversation without breaking the turn.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Get an API key
&lt;/h2&gt;

&lt;p&gt;Start by opening the Ace Data Cloud application list, entering an available application, and copying the API key.&lt;/p&gt;

&lt;p&gt;Treat the key like any other production credential:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;do not paste it into public logs;&lt;/li&gt;
&lt;li&gt;do not commit it to a repository;&lt;/li&gt;
&lt;li&gt;do not include it in screenshots;&lt;/li&gt;
&lt;li&gt;rotate it if you accidentally expose it.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Claude Desktop will store it as a static API key in the gateway configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Open Claude Desktop developer mode
&lt;/h2&gt;

&lt;p&gt;On the Claude Desktop login page, open the menu path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Help → Troubleshooting → Enable Developer Mode
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After developer mode is enabled, open:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Developer → Configure Third-Party Inference…
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the configuration surface you want for this tutorial. If you are looking at Claude Code settings or an MCP connector JSON file, you are in the wrong place for this particular guide.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Fill in the gateway settings
&lt;/h2&gt;

&lt;p&gt;In the Third-Party Inference configuration screen, select &lt;strong&gt;Gateway&lt;/strong&gt; and enter:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Gateway base URL: https://api.acedata.cloud
Gateway auth scheme: bearer
Credential kind: Static API key
Gateway API key: YOUR_API_KEY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then click &lt;strong&gt;Apply Changes&lt;/strong&gt;, followed by &lt;strong&gt;Save &amp;amp; Restart&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Do not skip the restart. A common failure mode with desktop integrations is changing a setting, testing immediately, and debugging a stale configuration. Restarting makes the verification step much less ambiguous.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Verify with a minimal prompt
&lt;/h2&gt;

&lt;p&gt;After Claude Desktop restarts, select an available model and create a new conversation.&lt;/p&gt;

&lt;p&gt;Use a minimal prompt first:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Reply only OK
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This checks the basic path before you introduce a larger prompt, files, or tool use. Once that works, perform a small tool task. The gateway documented for this setup supports streaming &lt;code&gt;/v1/messages&lt;/code&gt;, tool calling, and &lt;code&gt;tool_result&lt;/code&gt; continuation, so a tool task is an important second check.&lt;/p&gt;

&lt;p&gt;You can also inspect invocation records in Usage History on the platform side. If something fails, those records are more useful than guessing from the desktop UI alone.&lt;/p&gt;

&lt;h2&gt;
  
  
  What to check when it fails
&lt;/h2&gt;

&lt;p&gt;Here is the debugging order I would use before changing random settings.&lt;/p&gt;

&lt;h3&gt;
  
  
  401 errors
&lt;/h3&gt;

&lt;p&gt;A &lt;code&gt;401&lt;/code&gt; usually means the key is wrong or missing. Recheck that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the copied API key is complete;&lt;/li&gt;
&lt;li&gt;the auth scheme is exactly &lt;code&gt;bearer&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;the credential kind is &lt;code&gt;Static API key&lt;/code&gt;;&lt;/li&gt;
&lt;li&gt;the key was not pasted with extra whitespace.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not share the API key when asking for help.&lt;/p&gt;

&lt;h3&gt;
  
  
  Model not found
&lt;/h3&gt;

&lt;p&gt;If a model cannot be found, recheck the gateway configuration and fully restart Claude Desktop. Since the gateway supports &lt;code&gt;/v1/models&lt;/code&gt;, the model list is part of the integration path; a stale desktop state or wrong gateway URL can make this look like a model issue when it is actually a configuration issue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tool calls stop after the first call
&lt;/h3&gt;

&lt;p&gt;For agent-like workflows, the continuation step matters. This gateway supports tool calling and &lt;code&gt;tool_result&lt;/code&gt; continuation used by Claude Desktop. If a normal prompt works but tool use does not, test a very small tool task and then look at the invocation records for the trace ID.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prompt caching confusion
&lt;/h3&gt;

&lt;p&gt;The guide notes that prompt caching fields are retained. Cache write and read values both being &lt;code&gt;0&lt;/code&gt; does not mean that a cache hit occurred. Avoid treating those numbers as proof of caching behavior unless the surrounding usage records support that interpretation.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical verification checklist
&lt;/h2&gt;

&lt;p&gt;Before you consider the setup done, run through this short checklist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Gateway base URL is &lt;code&gt;https://api.acedata.cloud&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Auth scheme is &lt;code&gt;bearer&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Credential kind is &lt;code&gt;Static API key&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Claude Desktop was restarted after applying changes.&lt;/li&gt;
&lt;li&gt;A new conversation can answer &lt;code&gt;Reply only OK&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;A small tool task completes.&lt;/li&gt;
&lt;li&gt;Usage History shows invocation records.&lt;/li&gt;
&lt;li&gt;Any support report includes a trace ID, not an API key.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Closing thoughts
&lt;/h2&gt;

&lt;p&gt;The biggest trick with desktop AI configuration is knowing which layer you are editing. For this workflow, stay in Claude Desktop’s Third-Party Inference Gateway screen, keep the gateway values minimal, restart before testing, and verify both plain messages and tool continuation. The full Ace Data Cloud setup notes are here: &lt;a href="https://platform.acedata.cloud/documents/claude-desktop-gateway-integration" rel="noopener noreferrer"&gt;https://platform.acedata.cloud/documents/claude-desktop-gateway-integration&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devtools</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to Add Short Link Workflows to Claude Code with MCP</title>
      <dc:creator>Germey</dc:creator>
      <pubDate>Sun, 27 Sep 2026 01:06:35 +0000</pubDate>
      <link>https://dev.to/germey/how-to-add-short-link-workflows-to-claude-code-with-mcp-3f1b</link>
      <guid>https://dev.to/germey/how-to-add-short-link-workflows-to-claude-code-with-mcp-3f1b</guid>
      <description>&lt;p&gt;Long links are a tiny annoyance until they show up everywhere: PR descriptions, commit messages, README files, release notes, Slack threads, and internal docs. The practical goal of this guide is simple: let Claude Code shorten links from the terminal while you are already working on the surrounding text.&lt;/p&gt;

&lt;p&gt;ShortURL MCP is a small but useful example of what Model Context Protocol tools are good at. It does not try to replace your editor or your coding agent. It gives Claude Code one focused capability: turn long links into cleaner &lt;code&gt;https://surl.id/xxxxx&lt;/code&gt; links, including batch workflows for multiple URLs.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you can do
&lt;/h2&gt;

&lt;p&gt;After connecting the ShortURL MCP server, Claude Code can call link-shortening tools from a normal terminal session. The source document describes several everyday scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;shortening an issue or document link before putting it into a commit message;&lt;/li&gt;
&lt;li&gt;replacing multiple long external links in a README;&lt;/li&gt;
&lt;li&gt;preparing friendlier links before sending them to non-technical teammates;&lt;/li&gt;
&lt;li&gt;asking Claude Code to handle the link cleanup while it is already editing nearby Markdown.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The MCP server exposes these tools:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;shorturl_create&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Generate one short link&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;shorturl_batch_create&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Generate multiple short links at once&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;shorturl_get_api_info&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Get API information&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;shorturl_get_usage_guide&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Get the usage guide&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The important thing is not the short link itself. It is the workflow placement. If Claude Code is already drafting a PR description or editing a README, link shortening becomes one more tool call instead of a browser detour.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;ShortURL is exposed as a remote MCP server. Claude Code connects to it over HTTP, and your Ace Data Cloud API token is provided through the &lt;code&gt;Authorization&lt;/code&gt; header.&lt;/p&gt;

&lt;p&gt;The setup fields from the documentation are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MCP server URL: &lt;code&gt;https://shorturl.mcp.acedata.cloud/mcp&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Transport: &lt;code&gt;http&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Authorization header: &lt;code&gt;Authorization: Bearer YOUR_ACEDATACLOUD_API_KEY&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Claude Code command: &lt;code&gt;claude mcp add&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Verification command: &lt;code&gt;claude mcp list&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Expected server name after setup: &lt;code&gt;shorturl&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The documentation shows three configuration scopes: &lt;code&gt;local&lt;/code&gt;, &lt;code&gt;user&lt;/code&gt;, and &lt;code&gt;project&lt;/code&gt;. Use &lt;code&gt;local&lt;/code&gt; for a single project, &lt;code&gt;user&lt;/code&gt; if you want the server available across projects, and &lt;code&gt;project&lt;/code&gt; if a private team repository should carry the MCP configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configure it locally first
&lt;/h2&gt;

&lt;p&gt;For a first run, I prefer the &lt;code&gt;local&lt;/code&gt; scope. It keeps the setup attached to the current project directory and avoids changing your global Claude Code configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add shorturl &lt;span class="nt"&gt;--transport&lt;/span&gt; http https://shorturl.mcp.acedata.cloud/mcp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer YOUR_ACEDATACLOUD_API_KEY"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nb"&gt;local&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two details are easy to miss:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;-H&lt;/code&gt; must be uppercase. Lowercase &lt;code&gt;-h&lt;/code&gt; means &lt;code&gt;--help&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Keep the full header format: &lt;code&gt;Authorization: Bearer ...&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;After adding the server, verify that Claude Code can see it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If &lt;code&gt;shorturl&lt;/code&gt; shows &lt;code&gt;✓ Connected&lt;/code&gt;, the MCP handshake worked. If it does not, check the token, the server URL, and the scope before changing anything else.&lt;/p&gt;

&lt;h2&gt;
  
  
  Use it in a PR or commit workflow
&lt;/h2&gt;

&lt;p&gt;Imagine you are writing a commit message that references a long issue URL. Instead of manually opening a URL shortener, ask Claude Code directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Shorten this issue link; I want to put it in the commit message.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Claude Code can then call &lt;code&gt;shorturl_create&lt;/code&gt; and return a compact link in the &lt;code&gt;https://surl.id/xxxxx&lt;/code&gt; format described by the docs. The result is easier to scan in terminal output, commit bodies, chat messages, and changelog drafts.&lt;/p&gt;

&lt;p&gt;This is a good fit for links that are useful but noisy: GitHub issue filters, permanent line references, documentation pages with tracking parameters, or internal tools that generate very long URLs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Batch-clean links in Markdown
&lt;/h2&gt;

&lt;p&gt;The more interesting workflow is batch cleanup. The docs describe &lt;code&gt;shorturl_batch_create&lt;/code&gt; for shortening multiple links at once. That maps naturally to README and release-note maintenance.&lt;/p&gt;

&lt;p&gt;A useful prompt is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Help me replace all long external links in the README with short links.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In a real project, I would make that instruction more constrained:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Find external links in README.md that are longer than 100 characters. Use shorturl_batch_create to shorten them, then update the Markdown while keeping the link text unchanged.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That keeps the content readable while reducing link noise. It also gives Claude Code a clear editing rule: change the URL target, not the surrounding prose.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choose the right scope
&lt;/h2&gt;

&lt;p&gt;Use &lt;code&gt;local&lt;/code&gt; when you are testing or when only one repository needs short links.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;user&lt;/code&gt; when shortening links is part of your personal writing workflow across projects. The documentation notes that user-level configuration is written into the local &lt;code&gt;~/.claude.json&lt;/code&gt;, so projects opened later can see it.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;project&lt;/code&gt; for team workflows, but be careful with secrets. The documentation says project-level configuration is written into &lt;code&gt;.mcp.json&lt;/code&gt; in the project root. That can be useful in a private repository, but the real token should not be committed to a public repo. The first time Claude Code reads project-level configuration, it may show &lt;code&gt;Pending approval&lt;/code&gt;; you need to trust that configuration inside the session.&lt;/p&gt;

&lt;h2&gt;
  
  
  Final notes
&lt;/h2&gt;

&lt;p&gt;ShortURL MCP is intentionally small, which is why it is a good first MCP workflow to try in Claude Code. It has a clear input, a clear output, and a practical place in daily engineering writing. Start with &lt;code&gt;local&lt;/code&gt;, verify with &lt;code&gt;claude mcp list&lt;/code&gt;, and then use &lt;code&gt;shorturl_create&lt;/code&gt; or &lt;code&gt;shorturl_batch_create&lt;/code&gt; only where shorter links make the surrounding text easier to read.&lt;/p&gt;

&lt;p&gt;The original Ace Data Cloud setup reference is here: &lt;a href="https://platform.acedata.cloud/documents/claude-code-mcp-short-url" rel="noopener noreferrer"&gt;Claude Code with ShortURL MCP&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>devtools</category>
      <category>tutorial</category>
      <category>programming</category>
      <category>webdev</category>
    </item>
    <item>
      <title>A Practical Guide to Generating Short Videos with the Seedance API</title>
      <dc:creator>Germey</dc:creator>
      <pubDate>Sat, 26 Sep 2026 01:03:03 +0000</pubDate>
      <link>https://dev.to/germey/a-practical-guide-to-generating-short-videos-with-the-seedance-api-81o</link>
      <guid>https://dev.to/germey/a-practical-guide-to-generating-short-videos-with-the-seedance-api-81o</guid>
      <description>&lt;p&gt;If you have ever tried to turn a prompt, product idea, or reference image into a short video clip, the tricky part is often not the creative brief. It is getting the API shape right: which model supports which reference type, how &lt;code&gt;image_url&lt;/code&gt; is formatted, and where the finished video URL appears.&lt;/p&gt;

&lt;p&gt;This guide walks through a practical Seedance video generation workflow on Ace Data Cloud. We will send text and reference inputs to one endpoint, choose output settings, and read the &lt;code&gt;video_url&lt;/code&gt; from the result.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you can do
&lt;/h2&gt;

&lt;p&gt;The Seedance Videos API supports a few useful builder workflows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;text-to-video with a plain prompt&lt;/li&gt;
&lt;li&gt;image-to-video with a first frame, or first and last frames&lt;/li&gt;
&lt;li&gt;multimodal references with images, audio, or video&lt;/li&gt;
&lt;li&gt;optional audio generation on supported models&lt;/li&gt;
&lt;li&gt;asynchronous jobs through &lt;code&gt;callback_url&lt;/code&gt; or &lt;code&gt;async: true&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Seedance 2.5 video editing and extension with &lt;code&gt;reference_video&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The endpoint is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;POST https://api.acedata.cloud/seedance/videos
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The request headers are:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight http"&gt;&lt;code&gt;&lt;span class="err"&gt;authorization: Bearer ${bearer_token}
accept: application/json
content-type: application/json
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The core body field is &lt;code&gt;content&lt;/code&gt;, an array of typed inputs. Each item can be &lt;code&gt;text&lt;/code&gt;, &lt;code&gt;image_url&lt;/code&gt;, &lt;code&gt;audio_url&lt;/code&gt;, or &lt;code&gt;video_url&lt;/code&gt;. Image entries may also use roles such as &lt;code&gt;first_frame&lt;/code&gt;, &lt;code&gt;last_frame&lt;/code&gt;, or &lt;code&gt;reference_image&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  A minimal text-to-video request
&lt;/h2&gt;

&lt;p&gt;A basic request needs a &lt;code&gt;model&lt;/code&gt;, a prompt in &lt;code&gt;content&lt;/code&gt;, and output settings such as &lt;code&gt;resolution&lt;/code&gt;, &lt;code&gt;ratio&lt;/code&gt;, and &lt;code&gt;duration&lt;/code&gt;. For a quick 720p test, the documented example uses &lt;code&gt;doubao-seedance-2-0-fast-260128&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s1"&gt;'https://api.acedata.cloud/seedance/videos'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'authorization: Bearer ${bearer_token}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'accept: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'content-type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "content": [
      {
        "type": "text",
        "text": "A white ceramic coffee mug on a glossy marble countertop with soft morning window light. The camera slowly orbits 360 degrees around the mug, steam gently rising."
      }
    ],
    "model": "doubao-seedance-2-0-fast-260128",
    "resolution": "720p",
    "ratio": "16:9",
    "duration": 5
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A successful response includes &lt;code&gt;success&lt;/code&gt;, &lt;code&gt;task_id&lt;/code&gt;, &lt;code&gt;trace_id&lt;/code&gt;, and a &lt;code&gt;data&lt;/code&gt; object. The useful delivery field is usually &lt;code&gt;data.video_url&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"success"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"task_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"9777f36b-4f44-47ff-962d-45cd2f7aeaa8"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"trace_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ce5da2ca-6695-4459-9d2c-2ef9f86db752"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"succeeded"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"doubao-seedance-2-0-fast-260128"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"duration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"resolution"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"720p"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"ratio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"16:9"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"video_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://cdn.acedata.cloud/assets/examples/seedance/036f24ed-a9b1-49b3-92c4-30049a3bc152-102bf9f98e35.mp4"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Keep &lt;code&gt;task_id&lt;/code&gt; and &lt;code&gt;trace_id&lt;/code&gt; in your logs. They are useful when debugging failed jobs or correlating callbacks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choose model features intentionally
&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;model&lt;/code&gt; value determines which options are valid. The Seedance 1.x series includes models such as &lt;code&gt;doubao-seedance-1-0-pro-250528&lt;/code&gt; and &lt;code&gt;doubao-seedance-1-0-lite-i2v-250428&lt;/code&gt;. The 2.0 series includes &lt;code&gt;doubao-seedance-2-0-260128&lt;/code&gt;, &lt;code&gt;doubao-seedance-2-0-fast-260128&lt;/code&gt;, and &lt;code&gt;doubao-seedance-2-0-mini-260615&lt;/code&gt;. Seedance 2.5 uses &lt;code&gt;doubao-seedance-2-5-260628&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Some fields are model-specific. &lt;code&gt;generate_audio&lt;/code&gt; is supported by Seedance 1.5 Pro and the 2.x series, but not by the 1.0 series:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"doubao-seedance-1-5-pro-251215"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"content"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"text"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"A girl holds a fox, the wind blows her hair, you can hear the sound of the wind"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"generate_audio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ratio"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"16:9"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"duration"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Seedance 2.5, &lt;code&gt;omni_reference_task_type&lt;/code&gt; can be &lt;code&gt;auto&lt;/code&gt;, &lt;code&gt;reference&lt;/code&gt;, &lt;code&gt;edit&lt;/code&gt;, or &lt;code&gt;extend&lt;/code&gt;. Version 2.5 supports &lt;code&gt;output_format&lt;/code&gt; as &lt;code&gt;mp4&lt;/code&gt; or &lt;code&gt;mov&lt;/code&gt;, and supports &lt;code&gt;duration&lt;/code&gt; from 4 to 30 seconds or &lt;code&gt;-1&lt;/code&gt; where automatic duration is allowed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add reference images without 400 errors
&lt;/h2&gt;

&lt;p&gt;For image-to-video, &lt;code&gt;image_url&lt;/code&gt; must be an object with a &lt;code&gt;url&lt;/code&gt; field. Passing a raw string is not supported.&lt;/p&gt;

&lt;p&gt;Correct:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"image_url"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"image_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://ark-project.tos-cn-beijing.volces.com/doc_image/i2v_foxrgirl.png"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A simple Python request can combine that image with a prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;requests&lt;/span&gt;

&lt;span class="n"&gt;url&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://api.acedata.cloud/seedance/videos&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="n"&gt;headers&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;accept&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;authorization&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Bearer {token}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content-type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;application/json&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;payload&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;content&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;image_url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;image_url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;url&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://ark-project.tos-cn-beijing.volces.com/doc_image/i2v_foxrgirl.png&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;type&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;A girl holds a fox in her arms. As the camera slowly pulls away, her hair is gently blown by the wind. --ratio adaptive --dur 5&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;doubao-seedance-1-0-pro-250528&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;requests&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;headers&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you need strict first and last frames, use two &lt;code&gt;image_url&lt;/code&gt; items and set &lt;code&gt;role&lt;/code&gt; to &lt;code&gt;first_frame&lt;/code&gt; and &lt;code&gt;last_frame&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Multimodal references and validation
&lt;/h2&gt;

&lt;p&gt;Seedance 2.0 supports &lt;code&gt;reference_image&lt;/code&gt;, &lt;code&gt;reference_audio&lt;/code&gt;, and &lt;code&gt;reference_video&lt;/code&gt;. This helps when you want consistency in a subject, action, rhythm, or camera motion.&lt;/p&gt;

&lt;p&gt;Useful validation rules to add before sending the request:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Do not mix &lt;code&gt;first_frame&lt;/code&gt; / &lt;code&gt;last_frame&lt;/code&gt; with &lt;code&gt;reference_image&lt;/code&gt;, &lt;code&gt;reference_audio&lt;/code&gt;, or &lt;code&gt;reference_video&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Seedance 2.0 supports up to 9 reference images.&lt;/li&gt;
&lt;li&gt;Reference audio should be &lt;code&gt;wav&lt;/code&gt; or &lt;code&gt;mp3&lt;/code&gt;, 2–15 seconds per item, up to 3 items, and no more than 15 seconds total.&lt;/li&gt;
&lt;li&gt;Reference video should be &lt;code&gt;mp4&lt;/code&gt; or &lt;code&gt;mov&lt;/code&gt;, 2–15 seconds per item, up to 3 items, and no more than 15 seconds total.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A clean production flow is: create an internal job, submit &lt;code&gt;async: true&lt;/code&gt; or a &lt;code&gt;callback_url&lt;/code&gt;, store &lt;code&gt;task_id&lt;/code&gt; and &lt;code&gt;trace_id&lt;/code&gt;, then persist &lt;code&gt;data.video_url&lt;/code&gt; when the task succeeds. That keeps the model call separate from your UI and gives you enough metadata to retry or inspect failures.&lt;/p&gt;

&lt;p&gt;For the full parameter table and additional examples, see the &lt;a href="https://platform.acedata.cloud/documents/seedance-videos-integration" rel="noopener noreferrer"&gt;Seedance Videos API Integration Guide&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>tutorial</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>How to Configure Cline in VS Code with an OpenAI-Compatible Endpoint</title>
      <dc:creator>Germey</dc:creator>
      <pubDate>Fri, 25 Sep 2026 01:05:29 +0000</pubDate>
      <link>https://dev.to/germey/how-to-configure-cline-in-vs-code-with-an-openai-compatible-endpoint-1b2k</link>
      <guid>https://dev.to/germey/how-to-configure-cline-in-vs-code-with-an-openai-compatible-endpoint-1b2k</guid>
      <description>&lt;p&gt;Sometimes the fastest way to test a coding model is not to write a new integration, but to plug it into a tool you already use every day: VS Code.&lt;/p&gt;

&lt;p&gt;This guide walks through a practical setup for using Cline with Ace Data Cloud through Cline's &lt;strong&gt;OpenAI Compatible&lt;/strong&gt; provider. The goal is simple: configure the provider, verify the model can reply, and then confirm that file-oriented agent work is possible before you trust it on a real task.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you can do
&lt;/h2&gt;

&lt;p&gt;Cline is a VS Code extension for agent-style coding tasks. In this setup, Ace Data Cloud is used as the OpenAI-compatible endpoint behind Cline. The documented configuration is intentionally small:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;API Provider&lt;/td&gt;
&lt;td&gt;&lt;code&gt;OpenAI Compatible&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Base URL&lt;/td&gt;
&lt;td&gt;&lt;code&gt;https://api.acedata.cloud/v1&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API Key&lt;/td&gt;
&lt;td&gt;The API Key copied from the Ace Data Cloud application&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Model ID&lt;/td&gt;
&lt;td&gt;The model ID currently provided by the Coding Plan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom Headers&lt;/td&gt;
&lt;td&gt;Leave blank&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Set Azure API version&lt;/td&gt;
&lt;td&gt;Leave blank&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Use Azure Identity Authentication&lt;/td&gt;
&lt;td&gt;Disabled&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;This is enough to route Cline's model calls to the selected Coding Plan model without adding custom headers or Azure-specific settings.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;The setup has three moving parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An API Key from an Ace Data Cloud application.&lt;/li&gt;
&lt;li&gt;Cline's &lt;strong&gt;OpenAI Compatible&lt;/strong&gt; provider in VS Code.&lt;/li&gt;
&lt;li&gt;A model ID from the Coding Plan model directory.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The Base URL is the important fixed value:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://api.acedata.cloud/v1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The API Key is copied from the application list in the Ace Data Cloud console. The Model ID should match a model currently available in the Coding Plan. Keep the other provider fields unchanged unless you have a model-specific reason to adjust them later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: get the API Key
&lt;/h2&gt;

&lt;p&gt;Open the Ace Data Cloud application list and enter an available application. Copy the API Key from that application.&lt;/p&gt;

&lt;p&gt;Avoid putting this key in screenshots, public issues, shared repos, or example files. In documentation and team notes, use a placeholder such as:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;YOUR_ACEDATACLOUD_API_KEY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For Cline itself, paste the real value into the provider configuration field. The docs do not require a custom header for this setup, so keep &lt;strong&gt;Custom Headers&lt;/strong&gt; blank.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: configure Cline in VS Code
&lt;/h2&gt;

&lt;p&gt;Install and open Cline in VS Code. In the Cline panel, open the provider settings and fill in the fields from the guide:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;API Provider: OpenAI Compatible
Base URL: https://api.acedata.cloud/v1
API Key: &amp;lt;your copied API Key&amp;gt;
Model ID: &amp;lt;Coding Plan model ID&amp;gt;
Custom Headers: &amp;lt;blank&amp;gt;
Set Azure API version: &amp;lt;blank&amp;gt;
Use Azure Identity Authentication: Disabled
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a first pass, keep the remaining model capability settings at their defaults. The guide recommends adjusting those later only when you need image support or a larger context, and only according to the actual capabilities of the selected model.&lt;/p&gt;

&lt;p&gt;That order matters. First prove basic chat and tool behavior. Then tune model-specific capability switches.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: verify basic model access
&lt;/h2&gt;

&lt;p&gt;After saving the provider configuration, create a new Cline task and send:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Reply only OK
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a small but useful smoke test. If the provider is configured correctly, the model should respond with just &lt;code&gt;OK&lt;/code&gt;. If that fails, do not start debugging agent behavior yet. Fix connectivity first.&lt;/p&gt;

&lt;p&gt;The guide gives two common failure patterns:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;401&lt;/code&gt; usually means the Key is incorrect.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;404&lt;/code&gt; usually means the Base URL or Model ID is incorrect.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So if you see a &lt;code&gt;401&lt;/code&gt;, re-copy the API Key from the application. If you see a &lt;code&gt;404&lt;/code&gt;, check that the Base URL is exactly &lt;code&gt;https://api.acedata.cloud/v1&lt;/code&gt; and that the Model ID matches the model you intended to use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: verify file-oriented agent behavior
&lt;/h2&gt;

&lt;p&gt;A chat response proves the endpoint is reachable, but Cline is most useful when it can work with your project files. After the &lt;code&gt;Reply only OK&lt;/code&gt; smoke test passes, ask Cline to read a simple test file in the current workspace.&lt;/p&gt;

&lt;p&gt;For example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Read the README file in this workspace and summarize its main setup steps.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the model can chat but cannot operate on files, the guide recommends checking whether the selected model supports tool calling. This is a different class of problem from API credentials. A valid endpoint and key do not automatically mean every model has the same agent capabilities.&lt;/p&gt;

&lt;p&gt;You can also review call records in Usage History in the Ace Data Cloud console. That gives you a practical place to confirm requests are reaching the platform while you test different model IDs.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical debugging checklist
&lt;/h2&gt;

&lt;p&gt;When configuring a coding agent, it is easy to change too many variables at once. I would debug this setup in the following order:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Confirm &lt;strong&gt;API Provider&lt;/strong&gt; is &lt;code&gt;OpenAI Compatible&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Confirm &lt;strong&gt;Base URL&lt;/strong&gt; is exactly &lt;code&gt;https://api.acedata.cloud/v1&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Re-paste the API Key if you see &lt;code&gt;401&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Re-check the Model ID if you see &lt;code&gt;404&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Send &lt;code&gt;Reply only OK&lt;/code&gt; before trying file edits.&lt;/li&gt;
&lt;li&gt;If chat works but file operations do not, check the selected model's tool calling capability.&lt;/li&gt;
&lt;li&gt;Only then adjust optional model capability settings such as image support or larger context.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This keeps the setup boring, which is what you want from infrastructure inside an editor.&lt;/p&gt;

&lt;h2&gt;
  
  
  When this setup is useful
&lt;/h2&gt;

&lt;p&gt;This workflow is especially handy if your team already uses VS Code and wants a quick way to compare Coding Plan models inside a real coding assistant. You can start with a minimal provider configuration, run a tiny smoke test, and then graduate to repository-aware tasks once the model and tool calling behavior are confirmed.&lt;/p&gt;

&lt;p&gt;The full Ace Data Cloud setup reference for Cline is here: &lt;a href="https://platform.acedata.cloud/documents/cline-vscode-integration" rel="noopener noreferrer"&gt;https://platform.acedata.cloud/documents/cline-vscode-integration&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devtools</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to Add AI Music Generation to Gemini CLI with Suno MCP</title>
      <dc:creator>Germey</dc:creator>
      <pubDate>Thu, 24 Sep 2026 01:08:59 +0000</pubDate>
      <link>https://dev.to/germey/how-to-add-ai-music-generation-to-gemini-cli-with-suno-mcp-3oc6</link>
      <guid>https://dev.to/germey/how-to-add-ai-music-generation-to-gemini-cli-with-suno-mcp-3oc6</guid>
      <description>&lt;p&gt;If you already use Gemini CLI as a terminal assistant, the next useful step is not another chat window. It is giving that same terminal session a few real tools, so it can help you produce assets while you are still in the flow of building.&lt;/p&gt;

&lt;p&gt;This guide shows how to add Suno MCP to Gemini CLI through Ace Data Cloud. The practical result is simple: from a Gemini CLI conversation, you can ask for a short song, background music, lyrics, a cover, or an extension of an existing track.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you can do
&lt;/h2&gt;

&lt;p&gt;The source document describes a remote MCP server for Suno. Once it is configured in Gemini CLI, the assistant can call Suno-related tools from natural language prompts instead of making you switch to a separate UI.&lt;/p&gt;

&lt;p&gt;The documented MCP endpoint is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://suno.mcp.acedata.cloud/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Authentication is passed with an HTTP header:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Authorization: Bearer yourToken
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The tool list in the document includes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What it is for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;generate&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Generate a song from a description&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;custom&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Generate a song with custom lyrics and style&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;extend&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Extend an existing song&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;cover&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cover a song in a new style&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;lyrics&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Generate lyrics only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;upload_to_persona&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Register a Persona with vocal audio&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;query&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Query historical generation results&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That is enough for a practical builder workflow: write a tutorial, app demo, or game prototype, then create a matching audio draft without leaving the terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;Gemini CLI supports MCP servers. An MCP server is a tool provider that the model can call when it decides a task needs an external capability. In this case, the tool provider is the Suno MCP server hosted behind Ace Data Cloud.&lt;/p&gt;

&lt;p&gt;The configuration has two parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;the remote MCP URL&lt;/li&gt;
&lt;li&gt;the authorization header that carries your Ace Data Cloud token&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The one-command setup from the document is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gemini mcp add suno &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--transport&lt;/span&gt; http &lt;span class="se"&gt;\&lt;/span&gt;
  https://suno.mcp.acedata.cloud/mcp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--header&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer yourToken"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use a real token locally, but keep examples and documentation in the &lt;code&gt;yourToken&lt;/code&gt; form. Tokens should not be committed to a repository, pasted into public issues, or embedded in screenshots.&lt;/p&gt;

&lt;h2&gt;
  
  
  Alternative: edit the Gemini settings file
&lt;/h2&gt;

&lt;p&gt;If you prefer declarative configuration, the document also shows a &lt;code&gt;~/.gemini/settings.json&lt;/code&gt; entry. This is useful when you want a repeatable setup that is easy to review.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"mcpServers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"suno"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"httpUrl"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://suno.mcp.acedata.cloud/mcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"Authorization"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bearer yourToken"&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After saving the file, restart your &lt;code&gt;gemini&lt;/code&gt; session so the MCP server is loaded. I usually prefer starting with the CLI command for a quick test, then moving to the settings file once I know the endpoint and token are correct.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try a few useful prompts
&lt;/h2&gt;

&lt;p&gt;Once the server is mounted, the interaction can stay high level. You describe the musical goal, and Gemini CLI can choose the relevant Suno tool.&lt;/p&gt;

&lt;p&gt;For a short social or product demo asset:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Help me write a 30-second upbeat Chinese pop song with the theme "Camping with friends on the weekend."
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For background music under a screen recording:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Use Suno to create a lofi hip hop BGM for a programming tutorial video, without vocals.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For iterating on an existing track:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Extend this song (link xxx) from 30 seconds to 90 seconds, maintaining the original melody style.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are intentionally specific. “Make some music” is hard to evaluate. “30-second upbeat Chinese pop song,” “lofi hip hop BGM,” and “extend from 30 seconds to 90 seconds” give the tool enough context to produce something you can review.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical workflow for builders
&lt;/h2&gt;

&lt;p&gt;A small but useful workflow looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Write the script or demo flow in your project.&lt;/li&gt;
&lt;li&gt;Ask Gemini CLI to summarize the mood and pacing of the content.&lt;/li&gt;
&lt;li&gt;Turn that summary into a Suno prompt.&lt;/li&gt;
&lt;li&gt;Generate one or two drafts.&lt;/li&gt;
&lt;li&gt;If a draft is close, use &lt;code&gt;extend&lt;/code&gt; or &lt;code&gt;cover&lt;/code&gt; instead of starting over.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;query&lt;/code&gt; when you need to check previous generation results.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The key is to treat audio generation like an iteration loop, not a one-shot command. The first output tells you what to clarify: vocals or no vocals, duration, genre, language, and whether the piece should sit under narration or stand on its own.&lt;/p&gt;

&lt;h2&gt;
  
  
  When I would use each tool
&lt;/h2&gt;

&lt;p&gt;Use &lt;code&gt;generate&lt;/code&gt; when you have a style description but no lyrics. This is a good fit for BGM, short loops, or mood boards.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;custom&lt;/code&gt; when the words matter. If your demo video has a theme, tagline, or narrative arc, write or generate lyrics first, then pass the lyrics plus a style direction.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;lyrics&lt;/code&gt; when you are still drafting the concept. It lets you separate writing from audio production.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;extend&lt;/code&gt; when the first result is directionally right but too short. This is common for tutorial intros, product walkthroughs, and background tracks.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;cover&lt;/code&gt; when the composition is useful but the style is not. Instead of discarding the idea, try a new style pass.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;upload_to_persona&lt;/code&gt; only when you have appropriate rights to the vocal audio you are registering. That is an implementation detail, but it is also an important product boundary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the integration boring
&lt;/h2&gt;

&lt;p&gt;For production or team usage, keep the setup boring and explicit. Store the token outside version control, document the MCP URL, and write down which prompts produce good results for your content style. If multiple people use the same workflow, standardize a few prompt templates so outputs are easier to compare.&lt;/p&gt;

&lt;p&gt;This is where MCP feels natural: Gemini CLI stays the workspace, while Suno becomes one callable capability inside that workspace. You do not need a giant automation system to benefit from it; even a single terminal command plus a few disciplined prompts is enough to make the workflow useful.&lt;/p&gt;

&lt;p&gt;You can read the original setup notes here: &lt;a href="https://platform.acedata.cloud/documents/gemini-cli-mcp-suno" rel="noopener noreferrer"&gt;Gemini CLI with Suno MCP&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devtools</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to Track Async Image Generation Jobs with the Seedream Tasks API</title>
      <dc:creator>Germey</dc:creator>
      <pubDate>Wed, 23 Sep 2026 01:06:32 +0000</pubDate>
      <link>https://dev.to/germey/how-to-track-async-image-generation-jobs-with-the-seedream-tasks-api-5go6</link>
      <guid>https://dev.to/germey/how-to-track-async-image-generation-jobs-with-the-seedream-tasks-api-5go6</guid>
      <description>&lt;p&gt;Generating an image is only half of the integration. In a real product, you also need to know whether the job finished, how long it took, which prompt produced the result, and where the final image URL lives.&lt;/p&gt;

&lt;p&gt;This guide shows how to build that job-tracking layer with the Seedream Tasks API. The workflow is intentionally simple: start an image generation request elsewhere, save the returned task ID, then query task status until you have a stable result.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you can do
&lt;/h2&gt;

&lt;p&gt;The Seedream Tasks API is designed to retrieve execution details for tasks created by the Seedream Images Generation API.&lt;/p&gt;

&lt;p&gt;The documented task endpoint is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Base URL:&lt;/strong&gt; &lt;code&gt;https://api.acedata.cloud&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Endpoint:&lt;/strong&gt; &lt;code&gt;POST /seedream/tasks&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Auth header:&lt;/strong&gt; &lt;code&gt;authorization: Bearer {token}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Accept header:&lt;/strong&gt; &lt;code&gt;accept: application/json&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content type:&lt;/strong&gt; &lt;code&gt;content-type: application/json&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The request body changes depending on whether you are looking up one task or multiple tasks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Single task: &lt;code&gt;id&lt;/code&gt; plus &lt;code&gt;action: "retrieve"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Batch lookup: &lt;code&gt;ids&lt;/code&gt; plus &lt;code&gt;action: "retrieve_batch"&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That makes the API a good fit for backend queues, admin dashboards, cron-based polling, or any UI where users can return later and see whether their generated image is ready.&lt;/p&gt;

&lt;h2&gt;
  
  
  Store the task ID first
&lt;/h2&gt;

&lt;p&gt;When your image-generation call returns, persist the task ID immediately. The Seedream image response documented by Ace Data Cloud includes fields such as &lt;code&gt;success&lt;/code&gt;, &lt;code&gt;task_id&lt;/code&gt;, &lt;code&gt;trace_id&lt;/code&gt;, and &lt;code&gt;data&lt;/code&gt;. The task API uses that task ID as the lookup key.&lt;/p&gt;

&lt;p&gt;A minimal table for your own app might look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;image_jobs
- id
- provider_task_id
- trace_id
- prompt
- status
- output_image_url
- created_at
- finished_at
- elapsed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact database does not matter. What matters is that &lt;code&gt;provider_task_id&lt;/code&gt; stores the value you will later send as &lt;code&gt;id&lt;/code&gt; to &lt;code&gt;/seedream/tasks&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retrieve one task
&lt;/h2&gt;

&lt;p&gt;For a single job detail page, query one task by ID. The request body contains the task &lt;code&gt;id&lt;/code&gt; and an &lt;code&gt;action&lt;/code&gt; value of &lt;code&gt;retrieve&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s1"&gt;'https://api.acedata.cloud/seedream/tasks'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'accept: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'authorization: Bearer {token}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'content-type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "id": "a6e0d456-189b-4c78-9232-2fe72166ab39",
    "action": "retrieve"
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A successful response can include the generated result directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"success"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"task_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"84d1544a-9043-4dde-a98b-e889dacd75f6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"trace_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"176acf03-7ca7-4fc6-85db-e3724d4f59eb"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"prompt"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"a white siamese cat"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2048x2048"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"image_url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://platform.cdn.acedata.cloud/seedream/6e5f9085-cc4a-4801-b77b-31550129ff19.jpg"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a user-facing UI, the important field is &lt;code&gt;data[].image_url&lt;/code&gt;. Once that is present, you can mark your local job as complete and render the image. Keep &lt;code&gt;trace_id&lt;/code&gt; too; it is useful when debugging a failed or unexpected task.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retrieve many tasks at once
&lt;/h2&gt;

&lt;p&gt;Single-task polling is fine for a detail page. For an admin dashboard or worker process, batch retrieval is more efficient. The body uses &lt;code&gt;ids&lt;/code&gt; and &lt;code&gt;action: "retrieve_batch"&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"ids"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"84d1544a-9043-4dde-a98b-e889dacd75f6"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"84d1544a-9043-4dde-a98b-e889dacd75f6"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"retrieve_batch"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The documented batch response contains an &lt;code&gt;items&lt;/code&gt; array and a &lt;code&gt;count&lt;/code&gt;. Each item includes task metadata such as &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;api_id&lt;/code&gt;, &lt;code&gt;application_id&lt;/code&gt;, &lt;code&gt;created_at&lt;/code&gt;, &lt;code&gt;started_at&lt;/code&gt;, &lt;code&gt;finished_at&lt;/code&gt;, &lt;code&gt;elapsed&lt;/code&gt;, &lt;code&gt;credential_id&lt;/code&gt;, &lt;code&gt;request&lt;/code&gt;, &lt;code&gt;trace_id&lt;/code&gt;, &lt;code&gt;type&lt;/code&gt;, &lt;code&gt;user_id&lt;/code&gt;, and &lt;code&gt;response&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;That structure is useful because you can update local records in one pass:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;for item in response.items:
    job = find_job_by_provider_task_id(item.id)
    job.trace_id = item.trace_id
    job.started_at = item.started_at

    if item.finished_at exists:
        job.finished_at = item.finished_at
        job.elapsed = item.elapsed
        job.status = "finished"
        job.output_image_url = item.response.data[0].image_url
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The documentation notes that &lt;code&gt;finished_at&lt;/code&gt; and &lt;code&gt;elapsed&lt;/code&gt; are not returned if the task is not complete. That is a clean signal for your polling loop: if &lt;code&gt;finished_at&lt;/code&gt; is missing, leave the job in a running state and check again later.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical polling loop
&lt;/h2&gt;

&lt;p&gt;A basic backend loop can be conservative:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Insert a local job before or immediately after creating the image task.&lt;/li&gt;
&lt;li&gt;Save the returned &lt;code&gt;task_id&lt;/code&gt; as &lt;code&gt;provider_task_id&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Poll &lt;code&gt;/seedream/tasks&lt;/code&gt; with &lt;code&gt;action: "retrieve"&lt;/code&gt; for one item, or &lt;code&gt;retrieve_batch&lt;/code&gt; for many pending jobs.&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;finished_at&lt;/code&gt; exists, copy &lt;code&gt;elapsed&lt;/code&gt; and &lt;code&gt;response.data[0].image_url&lt;/code&gt; into your database.&lt;/li&gt;
&lt;li&gt;If an error comes back, store the &lt;code&gt;error.code&lt;/code&gt;, &lt;code&gt;error.message&lt;/code&gt;, and &lt;code&gt;trace_id&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The task API is especially helpful when you do not want to expose provider-specific details to your frontend. Your frontend can call your own &lt;code&gt;/jobs/:id&lt;/code&gt; endpoint, while your backend handles the Ace Data Cloud task lookup.&lt;/p&gt;

&lt;h2&gt;
  
  
  Error handling
&lt;/h2&gt;

&lt;p&gt;The documented error examples include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;400 token_mismatched&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;400 api_not_implemented&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;401 invalid_token&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;429 too_many_requests&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;500 api_error&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A failed response follows this shape:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"success"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"error"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"code"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"api_error"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"message"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"fetch failed"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"trace_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2cf86e86-22a4-46e1-ac2f-032c0f2a4e89"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In practice, handle these as job states rather than raw exceptions. A &lt;code&gt;401&lt;/code&gt; means the integration needs configuration. A &lt;code&gt;429&lt;/code&gt; should trigger backoff. A &lt;code&gt;500&lt;/code&gt; should be stored with the trace ID so the job can be retried or inspected.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where this fits in an app
&lt;/h2&gt;

&lt;p&gt;This pattern works well for tools where users do not expect instant completion: image editors, CMS media libraries, ecommerce asset tools, internal creative review systems, or batch generation scripts.&lt;/p&gt;

&lt;p&gt;The main idea is to separate creation from retrieval. The image generation endpoint starts the work; the task endpoint gives your application a reliable way to observe it.&lt;/p&gt;

&lt;p&gt;For the complete field reference and examples, see the source document: &lt;a href="https://platform.acedata.cloud/documents/seedream-tasks-integration" rel="noopener noreferrer"&gt;Seedream Tasks API integration guide&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>api</category>
      <category>tutorial</category>
      <category>devtools</category>
    </item>
    <item>
      <title>How to Add Seedream Image Tools to Gemini CLI with MCP</title>
      <dc:creator>Germey</dc:creator>
      <pubDate>Mon, 21 Sep 2026 01:03:51 +0000</pubDate>
      <link>https://dev.to/germey/how-to-add-seedream-image-tools-to-gemini-cli-with-mcp-4d37</link>
      <guid>https://dev.to/germey/how-to-add-seedream-image-tools-to-gemini-cli-with-mcp-4d37</guid>
      <description>&lt;p&gt;Voice cloning demos often skip the part that determines whether the result is usable: preparing a clean source recording and carrying the returned identity into the generation request correctly. This guide walks through that small but important pipeline, from a WAV or MP3 sample to a song generated with its private voice character.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx34mfno2i4wq1jo5o97h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fx34mfno2i4wq1jo5o97h.png" alt="Voice cloning to music API workflow" width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What you are building
&lt;/h2&gt;

&lt;p&gt;The workflow has two API calls against the base URL &lt;code&gt;https://api.acedata.cloud&lt;/code&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;POST /suno/voices&lt;/code&gt; accepts a public &lt;code&gt;audio_url&lt;/code&gt; and creates a voice character.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;POST /suno/audios&lt;/code&gt; accepts the resulting &lt;code&gt;persona_id&lt;/code&gt; together with a music prompt and a supported model.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The handoff between those calls is the key design detail. The cloning response also contains a generated &lt;code&gt;name&lt;/code&gt;, but your application should store and reference &lt;code&gt;persona_id&lt;/code&gt;. Uploaded voice characters are private resources, and they cannot be reused across accounts.&lt;/p&gt;

&lt;p&gt;Before implementing this, make consent part of the product flow. Only clone a voice you own or have explicit permission to use. That is not an API parameter, but it is a sensible boundary for any real application involving someone’s identity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: prepare a source recording that can pass verification
&lt;/h2&gt;

&lt;p&gt;The voice endpoint accepts a publicly accessible &lt;code&gt;audio_url&lt;/code&gt; pointing to a WAV or MP3 file. The supported duration is 10–240 seconds, while the practical recommendation is a clean 30–60 second sample.&lt;/p&gt;

&lt;p&gt;More audio is not automatically better. A short dry recording with one recognizable speaker or singer is preferable to a finished song. Avoid accompaniment, background noise, echo, reverb, multiple speakers, low volume, and unclear speech. Those conditions can cause cloning to fail or reduce the quality of later generations.&lt;/p&gt;

&lt;p&gt;In production, I would validate the file format and duration before submitting the request. I would also tell the user why a studio-like dry sample matters rather than returning a generic error after a long upload.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: create the private voice character
&lt;/h2&gt;

&lt;p&gt;Send the source file URL in &lt;code&gt;audio_url&lt;/code&gt;. The &lt;code&gt;name&lt;/code&gt; and &lt;code&gt;description&lt;/code&gt; fields are optional.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s1"&gt;'https://api.acedata.cloud/suno/voices'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'accept: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'authorization: Bearer {token}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'content-type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "audio_url": "{public_wav_or_mp3_url}",
    "name": "My Voice",
    "description": "Single clear voice example"
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A successful response follows this shape:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"success"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"task_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"0fa609a6-c8d9-4bb5-8574-e4c93bb55d02"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"persona_id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"1ab79a71-a229-4350-8f02-402ff02eac16"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"VOICE_20260803037676"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"is_public"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Persist &lt;code&gt;data.persona_id&lt;/code&gt;; do not treat the generated &lt;code&gt;name&lt;/code&gt; as the stable reference. The &lt;code&gt;is_public&lt;/code&gt; value is &lt;code&gt;false&lt;/code&gt; for a voice character created from uploaded audio.&lt;/p&gt;

&lt;p&gt;Voice cloning is compute-intensive, so a compliant sample can occasionally return a failure such as &lt;code&gt;voices_sound_different&lt;/code&gt;. The integration guidance recommends one or two automatic retries, including when retrying the same material. Keep that retry policy bounded: record the failure, retry briefly, and then ask for a cleaner sample instead of hiding a persistent input problem. Failed requests are not charged according to the integration document.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: generate music with the cloned voice
&lt;/h2&gt;

&lt;p&gt;Pass the stored identifier to the audio generation endpoint. Set &lt;code&gt;action&lt;/code&gt; to &lt;code&gt;generate&lt;/code&gt;, include a text &lt;code&gt;prompt&lt;/code&gt;, and choose a compatible model. Voice cloning works with &lt;code&gt;chirp-v4-5&lt;/code&gt; and later models such as &lt;code&gt;chirp-v5&lt;/code&gt; and &lt;code&gt;chirp-v5-5&lt;/code&gt;; it does not support &lt;code&gt;chirp-v4&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST &lt;span class="s1"&gt;'https://api.acedata.cloud/suno/audios'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'accept: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'authorization: Bearer {token}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s1"&gt;'content-type: application/json'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{
    "action": "generate",
    "model": "chirp-v5-5",
    "prompt": "A warm synth-pop song about city nights",
    "persona_id": "1ab79a71-a229-4350-8f02-402ff02eac16"
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The returned &lt;code&gt;data&lt;/code&gt; is an array. Each generated item can include fields such as &lt;code&gt;id&lt;/code&gt;, &lt;code&gt;title&lt;/code&gt;, &lt;code&gt;audio_url&lt;/code&gt;, &lt;code&gt;image_url&lt;/code&gt;, &lt;code&gt;model&lt;/code&gt;, &lt;code&gt;state&lt;/code&gt;, &lt;code&gt;prompt&lt;/code&gt;, and &lt;code&gt;duration&lt;/code&gt;. For an application, I would wait for &lt;code&gt;state&lt;/code&gt; to be &lt;code&gt;succeeded&lt;/code&gt; before exposing &lt;code&gt;audio_url&lt;/code&gt;, and keep the original &lt;code&gt;prompt&lt;/code&gt; beside the result so users can understand what produced it.&lt;/p&gt;

&lt;p&gt;The same &lt;code&gt;persona_id&lt;/code&gt; can also be used with the &lt;code&gt;cover&lt;/code&gt; action, but starting with &lt;code&gt;generate&lt;/code&gt; keeps the first integration easy to reason about: one owned source voice, one stored identifier, and one explicit music prompt.&lt;/p&gt;

&lt;h2&gt;
  
  
  A small production checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Validate WAV or MP3 and the 10–240 second duration range before calling the API.&lt;/li&gt;
&lt;li&gt;Prefer a 30–60 second dry, single-voice sample.&lt;/li&gt;
&lt;li&gt;Send bearer authentication in the &lt;code&gt;authorization&lt;/code&gt; header.&lt;/li&gt;
&lt;li&gt;Store &lt;code&gt;persona_id&lt;/code&gt;, not the automatically generated voice name.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;chirp-v4-5&lt;/code&gt; or a later supported model.&lt;/li&gt;
&lt;li&gt;Limit cloning retries to one or two attempts and surface actionable feedback.&lt;/li&gt;
&lt;li&gt;Keep the voice resource and generated output tied to the account that created them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;What I like about this workflow is that it stays understandable: the first request creates an identity token, and the second uses that token as one input to generation. If you are implementing it yourself, keep the consent and audio-quality checks as visible as the API calls; the full field-level reference is in the &lt;a href="https://platform.acedata.cloud/documents/suno-voices-integration" rel="noopener noreferrer"&gt;Ace Data Cloud voice cloning integration guide&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>tutorial</category>
      <category>devtools</category>
      <category>programming</category>
    </item>
    <item>
      <title>How to Add NanoBanana Image Editing to Claude Code with MCP</title>
      <dc:creator>Germey</dc:creator>
      <pubDate>Sun, 20 Sep 2026 01:04:15 +0000</pubDate>
      <link>https://dev.to/germey/how-to-add-nanobanana-image-editing-to-claude-code-with-mcp-i7e</link>
      <guid>https://dev.to/germey/how-to-add-nanobanana-image-editing-to-claude-code-with-mcp-i7e</guid>
      <description>&lt;p&gt;If your coding agent can write the feature but you still leave the terminal to make screenshots, page illustrations, or product mockups, MCP is a practical way to close that loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you can do
&lt;/h2&gt;

&lt;p&gt;NanoBanana is useful when the image task depends on understanding an existing image, not just generating something from scratch. In the Ace Data Cloud documentation, the examples are deliberately developer-friendly: put a phone from one image onto a desk in another image, remove a text watermark from an image, or generate an illustration for a 404 page.&lt;/p&gt;

&lt;p&gt;The workflow is simple: configure a remote MCP server once, then ask Claude Code for image work in natural language while it is already inside your project. The two exposed tools are:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What it does&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nanobanana_generate_image&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Text-to-image generation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;nanobanana_edit_image&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Image editing with support for multiple image inputs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The most important configuration details are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;MCP server URL: &lt;code&gt;https://nanobanana.mcp.acedata.cloud/mcp&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Transport: &lt;code&gt;http&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Auth header: &lt;code&gt;Authorization: Bearer YOUR_ACEDATACLOUD_API_KEY&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Claude Code command: &lt;code&gt;claude mcp add nanobanana&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Verification command: &lt;code&gt;claude mcp list&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A small but important detail: the docs call out that &lt;code&gt;-H&lt;/code&gt; must be uppercase. Lowercase &lt;code&gt;-h&lt;/code&gt; is interpreted as help, which is exactly the kind of tiny CLI mistake that makes MCP setup feel more mysterious than it really is.&lt;/p&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;Claude Code can read your repo, modify files, and run commands. MCP adds external tools to that same terminal-centered session. In this case, the external tool is NanoBanana, an image generation and editing MCP server backed by Google's Gemini image-understanding capabilities.&lt;/p&gt;

&lt;p&gt;You do not run the server locally. You register the remote MCP endpoint with Claude Code and pass an Ace Data Cloud API token through an HTTP authorization header. After that, Claude Code can discover the &lt;code&gt;nanobanana_*&lt;/code&gt; tools and call them when your prompt asks for image generation, image editing, or multi-image composition.&lt;/p&gt;

&lt;p&gt;That makes the pattern feel natural for builder workflows. You can work on a landing page, ask for a matching 404 illustration, save the generated asset, and keep going without switching contexts.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: Get an API token
&lt;/h2&gt;

&lt;p&gt;The documentation says to open the Ace Data Cloud console application list and copy an API token. Keep the real token out of public repos, screenshots, issues, and chat logs. In examples, use a placeholder like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;YOUR_ACEDATACLOUD_API_KEY
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One token can be used across Ace Data Cloud MCP servers, so you do not need a separate token just for NanoBanana.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 2: Add the MCP server to Claude Code
&lt;/h2&gt;

&lt;p&gt;For a quick trial in the current project, use the &lt;code&gt;local&lt;/code&gt; scope:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add nanobanana &lt;span class="nt"&gt;--transport&lt;/span&gt; http https://nanobanana.mcp.acedata.cloud/mcp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer YOUR_ACEDATACLOUD_API_KEY"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-s&lt;/span&gt; &lt;span class="nb"&gt;local&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;local&lt;/code&gt; when you are testing the setup in one repo. Claude Code writes the record into your local &lt;code&gt;~/.claude.json&lt;/code&gt; together with the current project path.&lt;/p&gt;

&lt;p&gt;If you expect to use NanoBanana from many projects, use the user-level scope:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add nanobanana &lt;span class="nt"&gt;--transport&lt;/span&gt; http https://nanobanana.mcp.acedata.cloud/mcp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer YOUR_ACEDATACLOUD_API_KEY"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-s&lt;/span&gt; user
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For team projects, there is also a project-level option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp add nanobanana &lt;span class="nt"&gt;--transport&lt;/span&gt; http https://nanobanana.mcp.acedata.cloud/mcp &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Authorization: Bearer YOUR_ACEDATACLOUD_API_KEY"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-s&lt;/span&gt; project
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The project scope writes configuration into &lt;code&gt;.mcp.json&lt;/code&gt; in the project root. That can be useful for private team repositories, but do not commit a real token. Use a placeholder or let each teammate add their own local secret.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3: Verify the connection
&lt;/h2&gt;

&lt;p&gt;After adding the server, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;claude mcp list
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A healthy setup should show &lt;code&gt;nanobanana&lt;/code&gt; as &lt;code&gt;✓ Connected&lt;/code&gt;. If it does not, check three things before changing anything else: the token, the remote service URL, and the scope you used when adding the server.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: Use it in real project tasks
&lt;/h2&gt;

&lt;p&gt;Once connected, you can ask Claude Code for image work the same way you ask it for code changes.&lt;/p&gt;

&lt;p&gt;For multi-image composition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Use NanoBanana to place the phone from the first image onto the desk in the second image. Match the angle and lighting so it looks natural.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For cleanup work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Edit this image to remove the text watermark in the lower-right corner, filling the area with the surrounding background.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a small web asset:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Generate an illustration of a small dinosaur squatting next to a crack in the ground, looking down. Use it as a 404 page illustration.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The point is not to replace design judgment. It is to keep asset iteration close to the code. When you are building a docs page, prototype, README, or empty state, the fastest useful image is often the one you can request without leaving the terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  A few practical notes
&lt;/h2&gt;

&lt;p&gt;Start with &lt;code&gt;local&lt;/code&gt; until you confirm that the server connects. Move to &lt;code&gt;user&lt;/code&gt; only when you know you want it available across projects. Use &lt;code&gt;project&lt;/code&gt; when the configuration itself is part of how your team works, and treat secrets carefully.&lt;/p&gt;

&lt;p&gt;Also, avoid hardcoding assumptions about the number of tools or older client behavior. The docs recommend checking the current connection state with &lt;code&gt;claude mcp list&lt;/code&gt; rather than relying on memory.&lt;/p&gt;

&lt;p&gt;If you want the exact setup reference, the Ace Data Cloud guide is here: &lt;a href="https://platform.acedata.cloud/documents/claude-code-mcp-nano-banana" rel="noopener noreferrer"&gt;https://platform.acedata.cloud/documents/claude-code-mcp-nano-banana&lt;/a&gt;&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devtools</category>
      <category>tutorial</category>
      <category>programming</category>
    </item>
    <item>
      <title>A Practical Guide to Generating Music from VS Code with MCP</title>
      <dc:creator>Germey</dc:creator>
      <pubDate>Thu, 17 Sep 2026 01:05:42 +0000</pubDate>
      <link>https://dev.to/germey/a-practical-guide-to-generating-music-from-vs-code-with-mcp-3413</link>
      <guid>https://dev.to/germey/a-practical-guide-to-generating-music-from-vs-code-with-mcp-3413</guid>
      <description>&lt;p&gt;You finish recording a programming walkthrough, play it back, and realize the tutorial is just your voice plus keyboard noise. Instead of breaking flow to hunt for background music, you can ask your editor agent to create a track from inside VS Code.&lt;/p&gt;

&lt;p&gt;This guide walks through the documented VS Code + Suno MCP setup: install the MCP extension, store the API key safely, verify it from GitHub Copilot Agent mode, and keep a manual &lt;code&gt;.vscode/mcp.json&lt;/code&gt; fallback for teams that prefer explicit project configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  What you can do
&lt;/h2&gt;

&lt;p&gt;The document describes a Suno MCP workflow for VS Code. The main use case is simple: let GitHub Copilot Chat in &lt;strong&gt;Agent&lt;/strong&gt; mode call Suno tools while you are still working in the editor.&lt;/p&gt;

&lt;p&gt;The extension ID is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;acedatacloud.mcp-suno
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The MCP server URL used by the optional manual config is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;https://suno.mcp.acedata.cloud/mcp
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Authorization header follows this shape:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Authorization: Bearer ${input:acedata-api-key}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The documented tools include:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;What it is for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;suno_generate_music&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Generate a complete song from a one-sentence description&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;suno_generate_custom_music&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use your own lyrics, style, and vocal type&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;suno_extend_music&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Continue a song from a specific time point&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;suno_cover_music&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Cover an existing song in a different style&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;suno_mashup_music&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Mash two songs into one&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;suno_stems_music&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Separate vocals and accompaniment&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;suno_generate_lyrics&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Generate lyrics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;suno_create_persona&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Save voice styles&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That is enough to support practical builder workflows: background music for a tutorial, a short intro for a demo video, or fast iteration on game and podcast audio ideas.&lt;/p&gt;

&lt;h2&gt;
  
  
  Install the VS Code extension
&lt;/h2&gt;

&lt;p&gt;Start with the extension path if you want the least configuration surface.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open the VS Code extension marketplace with &lt;code&gt;Cmd+Shift+X&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Search for &lt;code&gt;Suno MCP&lt;/code&gt;, or search directly for the extension ID &lt;code&gt;acedatacloud.mcp-suno&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Install&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Reload the VS Code window if prompted.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The key point is that the MCP integration lives where you are already working. You do not need to run a separate local MCP server process for this documented path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Store the API key safely
&lt;/h2&gt;

&lt;p&gt;After installing the extension, open the command palette with &lt;code&gt;Cmd+Shift+P&lt;/code&gt; and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Suno MCP: Set Ace Data Cloud API Key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Paste your Ace Data Cloud API key and press Enter. The document says the key is stored in VS Code SecretStorage / the system keychain, not written into your project files.&lt;/p&gt;

&lt;p&gt;If you need to rotate or replace it later, run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Suno MCP: Clear Ace Data Cloud API Key
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then set the key again. This is a good habit if you test with temporary credentials, move between machines, or accidentally paste the wrong key.&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify it from Copilot Agent mode
&lt;/h2&gt;

&lt;p&gt;Open GitHub Copilot Chat and switch to &lt;strong&gt;Agent&lt;/strong&gt; mode. Then ask for a task that clearly mentions &lt;code&gt;suno&lt;/code&gt;, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Use suno to help me generate a light and cheerful background music track for a programming tutorial, with a steady rhythm that does not distract from narration.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first call should route through the plugin and use the saved API key. For a short demo video, you might ask:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Generate a 20-second sci-fi opening music, primarily with electronic synthesizers, powerful but not noisy.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a podcast or branded intro, use the custom-music path:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Help me generate a song with custom lyrics. Lyrics: The moment the compilation passed, the world suddenly fell silent. Style: Lo-fi hip hop, lazy atmosphere.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The practical pattern is to describe the job as you would describe it to an editor: duration, mood, role in the video, and what the track should avoid. “Background music for narration” is a very different prompt from “energetic product launch intro.”&lt;/p&gt;

&lt;h2&gt;
  
  
  Optional: keep a manual &lt;code&gt;.vscode/mcp.json&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;If you prefer project-level configuration, the document also shows a manual MCP config. Create &lt;code&gt;.vscode/mcp.json&lt;/code&gt; and use an input prompt for the key instead of hardcoding the secret:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"servers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"suno"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"http"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"url"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://suno.mcp.acedata.cloud/mcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"headers"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"Authorization"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Bearer ${input:acedata-api-key}"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"inputs"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"acedata-api-key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"promptString"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Ace Data Cloud API Key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"password"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This version is useful when you want the MCP server definition to travel with a private repository while still asking each developer to provide their own key. The important part is the &lt;code&gt;${input:acedata-api-key}&lt;/code&gt; placeholder: it keeps the real value out of Git.&lt;/p&gt;

&lt;h2&gt;
  
  
  Useful workflows to try
&lt;/h2&gt;

&lt;p&gt;Here are three concrete ways I would use this in a builder workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Add quiet BGM to a coding tutorial
&lt;/h3&gt;

&lt;p&gt;Ask for a light, steady, non-distracting track. Mention narration explicitly. If the first version feels too busy, ask for less percussion or a slower rhythm.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Create a short demo-day intro
&lt;/h3&gt;

&lt;p&gt;For a product demo, ask for a 20-second opener and specify instrumentation. The document's example uses electronic synthesizers and a powerful-but-not-noisy direction, which is a good constraint for a tech demo.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Iterate on an existing track
&lt;/h3&gt;

&lt;p&gt;If a section works but the energy drops later, use &lt;code&gt;suno_extend_music&lt;/code&gt; conceptually through Copilot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Continue this song starting from 01:40, speed up the rhythm, and add more beats and orchestral crescendos.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is where editor-native generation feels useful: you can keep notes, scripts, and prompts in the same workspace as the video or tutorial project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrap-up
&lt;/h2&gt;

&lt;p&gt;The smallest useful path is: install &lt;code&gt;acedatacloud.mcp-suno&lt;/code&gt;, set the API key from the command palette, switch Copilot Chat to Agent mode, and make one narrow request for a real piece of background music. If your team prefers explicit config, use &lt;code&gt;.vscode/mcp.json&lt;/code&gt; with a password input instead of committing secrets.&lt;/p&gt;

&lt;p&gt;The full setup details are in the &lt;a href="https://platform.acedata.cloud/documents/vscode-mcp-suno" rel="noopener noreferrer"&gt;VS Code with Suno MCP documentation&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>devtools</category>
      <category>tutorial</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
