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