Monday, September 01, 2025

Revolutionizing UI Development with AI: A Look at Stagewise

 AI is already a powerful force in backend and middleware development, but its application in the frontend, particularly with frameworks like Vue, React, and Angular, has a unique set of challenges. While large language models (LLMs) can generate UI based on training data, the real complexity arises when you need to modify an existing UI. A seemingly simple change could ripple through the entire project, creating a tangled mess that’s a nightmare to untangle. This is where a tool like Stagewise comes in, acting as an AI-powered co-pilot for UI developers.

Lets try to integrate the same. As shown below we have simple nextjs useclient exmaple that increase the counter by one when we click on it.

Stagewise works on top of your existing project, running on a separate port so it doesn’t interfere with your current development environment. It’s designed for simple integration, using npx so there’s no need to install additional npm packages. It will, however, prompt you to save a stagewise.json file in your project for future reference.


Getting Started with Stagewise

Let’s walk through an example using a simple Next.js application. We’ll start with a basic counter component that increments a number on a button click.

  1. Start your local app in dev mode. pnpm dev # or npm run dev
  2. Open a new terminal in your project directory. cd C:\vscode-nextjs-workspace\siddhunextjsproject
  3. Run Stagewise. npx stagewise@latest

The first time you run it, Stagewise will ask you to log in with your Google account. After that, it will open your application on a new port (typically 3001) and display an interactive chat box that allows you to interact with your UI using AI.


Making Changes with AI Prompts

Now, let’s use the Stagewise chat box to make a UI change. Imagine you want to change the button color to green and add a parrot icon. Instead of manually editing the code, you simply type your request into the chat box:

Prompt: “Change the button color to green with a parrot icon.”

Stagewise will then analyze your UI and code, make the necessary modifications, and show you a preview of the changes. It will modify the relevant files, making the requested updates to your UI.


Fine-Tuning Changes with Element Selection

What if you want to be more specific and only change a particular element? Stagewise allows you to do that as well. You can select a specific div or element directly in the UI and then provide a prompt for a targeted change.

For example, you could select a block of text and then prompt the AI:

Prompt: “Change the font to Comic Sans and make it red.”

Stagewise will apply these changes only to the selected element, providing a level of control and precision that’s difficult to achieve with general-purpose AI tools.

Stagewise acts as a safeguard, ensuring that small UI tweaks don’t become large-scale headaches. By allowing you to make targeted, AI-powered changes, it helps you maintain control over your codebase while accelerating your development workflow.


This example project’s source code is available on GitHub: https://github.com/shdhumale/siddhunextjsproject.git

Tuesday, August 19, 2025

Seamlessly Integrate Cursor Rules into Your Roo Code Extension for VS Code

 

How to Create Custom LLM Rules in VS Code with Roo Code

As developers, we’re always looking for ways to tailor our tools to our specific workflows. When working with large language models (LLMs) in Visual Studio Code, the Roo Code extension is a powerful tool. While it comes with five default roles—Architect, Code, Ask, Debug, and Orchestra—you’ve likely encountered a need for more specialized rules to perfectly fit your development, testing, or other software development tasks.

This is where custom rules come in. If you’ve used the Cursor editor, you may be familiar with the various .mdc rule files available on GitHub. These files allow you to define custom rules for specific scenarios. The great news is that Roo Code can use these same .mdc files, allowing you to leverage a vast collection of community-made rules.

https://github.com/PatrickJS/awesome-cursorrules/tree/main
https://github.com/sanjeed5/awesome-cursor-rules-mdc
https://cursor.directory/rules


Implementing a Custom Rule

Let’s walk through a simple example of how to implement a custom rule from the community within the Roo Code extension. We’ll use the python.mdc rule file from PatrickJS’s awesome-cursorrules repository.

1. Find your rule file.
Navigate to the python.mdc file in the following GitHub repository:

2. Copy the content.
Open the file and copy the entire content.

3. Create a new custom rule in VS Code.
In VS Code, open the Command Palette (Ctrl/Cmd + Shift + P) and search for “Roo Code: Create Custom Role.”

4. Name and paste the rule.
Give your new rule a descriptive name, like “Python,” and press Enter. A new file will open. Paste the content you copied from the python.mdc file into this new file.

5. Save the file.
Save the file. Your new custom rule is now ready to use within the Roo Code extension. You should now be able to select and use your custom “Python” rule for your projects.

This process gives you the flexibility to import any .mdc rule file you find, allowing you to customize your LLM experience in VS Code to an unprecedented degree.

Roo code extension is capable of using this rule *.mdc files as their own roocode rule files.

Lets see how we can implement one of the rule file python.mdc of cursor inside roocode extension in vscode.

Follow the simple steps.

Finally start using the rule you have created just now. FYI we have used the python.mdc rule given in
https://github.com/PatrickJS/awesome-cursorrules/tree/main/rules-new/python.mdc

So in short follow the below given step to configure rule of cursor in roo code extension in vscode


✅Step 1: Install the Roo Code Extension

If you haven’t already, the first step is to install the Roo Code extension from the VS Code Marketplace.

  1. Open VS Code.
  2. Go to the Extensions view by pressing Ctrl+Shift+X.
  3. Search for “Roo Code” by RooVeterinaryInc.
  4. Click Install.
  5. Reload VS Code if prompted.

✅Step 2: Set Up Your Rule Directory Structure

To integrate your custom rules, you need to create a specific directory structure within your project.

  1. In the root directory of your project, create a new folder named .roo/.
  2. Inside the .roo/ folder, create mode-specific subfolders for your rules. For this guide, we’ll create a folder for a custom mode called python-dev to house our Python rule.

Your directory structure should look something like this:

1
2
.roo/
└── rules-python-dev/
  1. Now, download the python.mdc file from the repository and place it inside the newly created .roo/rules-python-dev/ folder.

Note: If you use both Cursor and Roo Code, you can use symbolic links to point to the .mdc files in your .cursor/rules/ directory, which helps maintain consistency and avoid duplication.


✅Step 3: Create a Custom Mode in Roo Code

With your rule file in place, you can now create a custom mode in Roo Code that links to it.

  1. Open the Roo Code panel in VS Code.
  2. Navigate to the Prompts (book icon).
  3. Click the + button to add a new custom mode.
  4. Fill in the following details for your new mode:
    • Name: Python Dev
    • Slug: python-dev
    • Role Definition: An expert Python developer. (or a description that fits your needs)
    • Available Tools: None (or select tools as needed for your workflow)
    • Custom Instructions: Link to the rule file you just added by entering its path: .roo/rules-python-dev/python.mdc.

✅Step 4: Start Using Your Custom Rule

Once your new custom mode is set up, you can start using it to interact with your codebase. Roo Code will automatically apply the rules defined in the python.mdc file whenever you activate the Python Dev mode. This allows you to leverage the power of custom rules to streamline tasks, maintain consistency, and enhance your overall coding experience with LLMs.

Monday, August 11, 2025

Building a Modular System: Local FASTMCP Client & Server with ADK Agents

 In the world of AI applications, building robust and scalable systems often means connecting different services and agents. This blog post will walk you through a practical example of how to integrate a FASTMCP server with Google ADK agents, running locally and communicating with a FASTMCP client that is also running on your machine. The goal is to show how you can create a modular system where agents can communicate with each other through a well-defined protocol.

The Architecture: A Two-Part System
Our setup consists of two main Python scripts, each with a distinct role:

restapi-mcp-adk-client.py (The FASTMCP Server): This script acts as our backend. It’s a FASTMCP server that exposes a single tool. This tool’s job is to fetch data from an external REST API, but it doesn’t do the work itself. Instead, it delegates that task to a Google ADK agent. This demonstrates how a FASTMCP tool can be a gateway to a more complex, agent-driven process.

restapi-mcp-adk-server.py (The FASTMCP Client): This is our frontend or the entry point for the user. It also contains an ADK agent, which is the one you will interact with. When you ask this agent to get data, it will intelligently decide to use a tool that connects to our FASTMCP server from the first script.

This architecture creates a chain of command: User -> Client ADK Agent -> FASTMCP Client -> FASTMCP Server -> Server ADK Agent -> External REST API.

Code Breakdown
Let’s look at the code for each component.

  1. The FASTMCP Server with ADK Agent
    This script sets up the server. The get_objects_by_id_using_adk_agent function is the core of our server’s toolset. It’s marked with @mcp.tool() and, importantly, it uses an ADK agent (call_mcp_server_agent) to handle the actual API call.
    restapi-mcp-adk-client.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
from fastmcp import FastMCP, Context
import httpx
import asyncio
from fastmcp import Client
import google.genai as genai
from typing import Any
from google.genai import types
from dotenv import load_dotenv
 
load_dotenv()
 
from google.adk.agents import LlmAgent
from pydantic import BaseModel, Field
 
from google.adk.agents import Agent
from google.adk.events import Event
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
 
mcp = FastMCP(
    name="RESTful API Wrapper <img draggable="false" role="img" class="emoji" alt="🌐" src="https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/svg/1f310.svg">",
)
 
 
APP_NAME = "MCP_SERVER_WITH_ADK_AGENT"
USER_ID = "1234"
SESSION_ID = "session1234"
 
'''
async def get_objects_by_ids(ids: list[str], ctx: Context):
    query = "&".join([f"id={i}" for i in ids])
    async with httpx.AsyncClient() as client:
        resp = await client.get(f"{BASE_URL}?{query}")
        print("get_objects_by_ids",resp.json())
    return resp.json()
         
'''
async def get_object_by_id(object_id: str):
   async with httpx.AsyncClient() as client:
        resp = await client.get(f"{BASE_URL}/{object_id}")
        print("get_object_by_id",resp.json())
        return resp.json()
 
call_mcp_server_agent = LlmAgent(
    model="gemini-2.0-flash",
    name="assistant",
    description="This agent is used to send data to FASTMCP client",
    instruction="""Help user to fetch the data from the RESTAPI and send it to the FASTMCP Client.
    When the user asks to fetch data for a specific object ID, use the `get_object_by_id` tool and pass the ID to it.
    """,
    tools=[get_object_by_id],
)
 
# Session and Runner
async def setup_session_and_runner():
    session_service = InMemorySessionService()
    session = await session_service.create_session(app_name=APP_NAME, user_id=USER_ID, session_id=SESSION_ID)
    if call_mcp_server_agent:
        runner = Runner(agent=call_mcp_server_agent, app_name=APP_NAME, session_service=session_service)
    return session, runner
 
async def get_agent_async(query):
    content = types.Content(role='user', parts=[types.Part(text=query)])
    session, runner = await setup_session_and_runner()
    events = runner.run_async(user_id=USER_ID, session_id=SESSION_ID, new_message=content)
 
    final_response = "Agent did not produce a final response."
    async for event in events:
        # You can uncomment the following line to see the full event flow for debugging
        # print(f"DEBUG Event: {event.model_dump_json(indent=2, exclude_none=True)}")
        if event.is_final_response() and event.content and event.content.parts:
            print(f"Potential final response from [{event.author}]: {event.content.parts[0].text}")
            final_response = event.content.parts[0].text
            #print final_response
            print(f"final_response",final_response)
    return final_response
     
@mcp.tool()
async def get_objects_by_id_using_adk_agent(object_id: str,ctx: Context):
    print(f"object_id:::::::::::::::::",object_id)
    final_result = await get_agent_async(f"Fetch the data for object_id {object_id}, pass the id to get_object_by_id tool")
    return final_result
 
if __name__ == "__main__":
    #mcp.run(transport="streamable-http", host="127.0.0.1", port=8001, path="/mcp")
    mcp.run()
  1. The FASTMCP Client with ADK Agent
    This script is the entry point. Its ADK agent is configured with a tool called get_mcp_data. This tool is where the magic happens—it uses fastmcp.Client to make a call to the server we defined above.
    restapi-mcp-adk-server.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import asyncio
from fastmcp import Client
from typing import Any
from google.genai import types
from dotenv import load_dotenv
 
from google.adk.agents import LlmAgent
from pydantic import BaseModel, Field
 
from google.adk.agents import Agent
from google.adk.events import Event
from google.adk.runners import Runner
from google.adk.sessions import InMemorySessionService
 
APP_NAME = "CALL_MCP_SERVER"
USER_ID = "1234"
SESSION_ID = "session1234"
 
async def get_mcp_data(object_id: str) -> dict:
    """Fetches an object by its ID from the MCP server."""
    print(f"Tool 'get_mcp_data' called with object_id: {object_id}")
    async with Client("restapi-mcp-adk-server.py") as client:
        single = await client.call_tool("get_objects_by_id_using_adk_agent", {"object_id": object_id})
        print("Fetched single:", single)
        return single
         
call_mcp_server_adk_agent = LlmAgent(
    model="gemini-2.0-flash",
    name="assistant",
    description="This agent is used to get data using FASTMCP client by calling the FASTMCP server ",
    instruction="""Help user to fetch the data from the FASTMCP Server using FASTMCP Client.
    When the user asks to fetch data for a specific object ID, use the `get_mcp_data` tool and pass the ID to it.
    """,
    tools=[get_mcp_data],
)
     
# Session and Runner
async def setup_session_and_runner():
    session_service = InMemorySessionService()
    session = await session_service.create_session(app_name=APP_NAME, user_id=USER_ID, session_id=SESSION_ID)
    runner = Runner(agent=call_mcp_server_adk_agent, app_name=APP_NAME, session_service=session_service)
    return session, runner
  
async def get_agent_async(query):
    content = types.Content(role='user', parts=[types.Part(text=query)])
    session, runner = await setup_session_and_runner()
    events = runner.run_async(user_id=USER_ID, session_id=SESSION_ID, new_message=content)
 
    final_response = "Agent did not produce a final response."
    async for event in events:
        # You can uncomment the following line to see the full event flow for debugging
        # print(f"DEBUG Event: {event.model_dump_json(indent=2, exclude_none=True)}")
        if event.is_final_response() and event.content and event.content.parts:
            print(f"Potential final response from [{event.author}]: {event.content.parts[0].text}")
            final_response = event.content.parts[0].text
     
    return final_response
 
  
if __name__ == "__main__":
    final_result = asyncio.run(get_agent_async("Fetch the data for object_id 2"))
    print(f"\n--- Script Finished ---\nFinal returned value: {final_result}")

Putting It All Together: The Execution Flow
When you run restapi-mcp-adk-server.py, the following sequence of events occurs, as shown in your output:

The client script starts and sends the query “Fetch the data for object_id 2” to its ADK agent.

The client ADK agent recognizes that it needs to fetch data and calls its get_mcp_data tool.

The get_mcp_data tool, acting as a FASTMCP client, initiates a call to the FASTMCP server (restapi-mcp-adk-client.py). It specifically calls the tool named get_objects_by_id_using_adk_agent with the object_id of 2.

The server receives this call, and its ADK agent takes over. It executes its own internal tool, get_object_by_id, passing it the id of 2.

get_object_by_id makes an HTTP request to the external https://api.restful-api.dev/objects/2 endpoint.

The external API returns the data, which is then passed back up the chain.

Finally, the client ADK agent receives the response and presents the final, conversational output: “OK. I have fetched the data for object ID 2. The object’s name is Apple iPhone 12 Mini, 256GB, Blue and its data is None.”

This example showcases the power of combining these technologies to build a system where different agents and services can collaborate seamlessly through a standardized tool-calling protocol.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
output:-
 
(.venv) C:\vscode-python-workspace\adkagent>python restapi-mcp-adk-client.py
C:\vscode-python-workspace\adkagent\.venv\Lib\site-packages\pydantic\_internal\_fields.py:198: UserWarning: Field name "config_type"
 in "SequentialAgent" shadows an attribute in parent "BaseAgent"
  warnings.warn(
Warning: there are non-text parts in the response: ['function_call'], returning concatenated text result from text parts. Check the
full candidates.content.parts accessor to get the full model response.
Tool 'get_mcp_data' called with object_id: 2
Fetched single: CallToolResult(content=[TextContent(type='text', text="OK. I have fetched the data for object ID 2. The object's nam
e is Apple iPhone 12 Mini, 256GB, Blue and its data is None.\n", annotations=None, meta=None)], structured_content=None, data=None,
is_error=False)
Potential final response from [assistant]: OK. I have fetched the data for object ID 2. The object's name is Apple iPhone 12 Mini, 2
56GB, Blue and its data is None.
 
 
--- Script Finished ---
Final returned value: OK. I have fetched the data for object ID 2. The object's name is Apple iPhone 12 Mini, 256GB, Blue and its da
ta is None.
 
 
(.venv) C:\vscode-python-workspace\adkagent>

source code :- https://github.com/shdhumale/app.git