Add MCP support (#1028)

This commit is contained in:
Will Chen
2025-09-19 15:43:39 -07:00
committed by GitHub
parent 7b160b7d0b
commit 6d3c397d40
39 changed files with 3865 additions and 650 deletions

View File

@@ -330,7 +330,7 @@ export class PageObject {
await this.page.getByRole("button", { name: "Import" }).click();
}
async selectChatMode(mode: "build" | "ask") {
async selectChatMode(mode: "build" | "ask" | "agent") {
await this.page.getByTestId("chat-mode-selector").click();
await this.page.getByRole("option", { name: mode }).click();
}
@@ -685,11 +685,16 @@ export class PageObject {
await this.page.getByRole("button", { name: "Back" }).click();
}
async sendPrompt(prompt: string) {
async sendPrompt(
prompt: string,
{ skipWaitForCompletion = false }: { skipWaitForCompletion?: boolean } = {},
) {
await this.getChatInput().click();
await this.getChatInput().fill(prompt);
await this.page.getByRole("button", { name: "Send message" }).click();
await this.waitForChatCompletion();
if (!skipWaitForCompletion) {
await this.waitForChatCompletion();
}
}
async selectModel({ provider, model }: { provider: string; model: string }) {

49
e2e-tests/mcp.spec.ts Normal file
View File

@@ -0,0 +1,49 @@
import path from "path";
import { test } from "./helpers/test_helper";
import { expect } from "@playwright/test";
test("mcp - call calculator", async ({ po }) => {
await po.setUp();
await po.goToSettingsTab();
await po.page.getByRole("button", { name: "Tools (MCP)" }).click();
await po.page
.getByRole("textbox", { name: "My MCP Server" })
.fill("testing-mcp-server");
await po.page.getByRole("textbox", { name: "node" }).fill("node");
const testMcpServerPath = path.join(
__dirname,
"..",
"testing",
"fake-stdio-mcp-server.mjs",
);
console.log("testMcpServerPath", testMcpServerPath);
await po.page
.getByRole("textbox", { name: "path/to/mcp-server.js --flag" })
.fill(testMcpServerPath);
await po.page.getByRole("button", { name: "Add Server" }).click();
await po.page
.getByRole("button", { name: "Add Environment Variable" })
.click();
await po.page.getByRole("textbox", { name: "Key" }).fill("testKey1");
await po.page.getByRole("textbox", { name: "Value" }).fill("testValue1");
await po.page.getByRole("button", { name: "Save" }).click();
await po.goToAppsTab();
await po.selectChatMode("agent");
await po.sendPrompt("[call_tool=calculator_add]", {
skipWaitForCompletion: true,
});
// Wait for consent dialog to appear
const alwaysAllowButton = po.page.getByRole("button", {
name: "Always allow",
});
await expect(alwaysAllowButton).toBeVisible();
// Make sure the tool call doesn't execute until consent is given
await po.snapshotMessages();
await alwaysAllowButton.click();
await po.sendPrompt("[dump]");
await po.snapshotServerDump("all-messages");
});

View File

@@ -0,0 +1,7 @@
- paragraph: "[call_tool=calculator_add]"
- img
- text: Tool Call
- img
- text: testing-mcp-server calculator_add
- img
- text: less than a minute ago

View File

@@ -0,0 +1,80 @@
===
role: system
message:
You are an AI App Builder Agent. Your role is to analyze app development requests and gather all necessary information before the actual coding phase begins.
## Core Mission
Determine what tools, APIs, data, or external resources are needed to build the requested application. Prepare everything needed for successful app development without writing any code yourself.
## Tool Usage Decision Framework
### Use Tools When The App Needs:
- **External APIs or services** (payment processing, authentication, maps, social media, etc.)
- **Real-time data** (weather, stock prices, news, current events)
- **Third-party integrations** (Firebase, Supabase, cloud services)
- **Current framework/library documentation** or best practices
### Use Tools To Research:
- Available APIs and their documentation
- Authentication methods and implementation approaches
- Database options and setup requirements
- UI/UX frameworks and component libraries
- Deployment platforms and requirements
- Performance optimization strategies
- Security best practices for the app type
### When Tools Are NOT Needed
If the app request is straightforward and can be built with standard web technologies without external dependencies, respond with:
**"Ok, looks like I don't need any tools, I can start building."**
This applies to simple apps like:
- Basic calculators or converters
- Simple games (tic-tac-toe, memory games)
- Static information displays
- Basic form interfaces
- Simple data visualization with static data
## Critical Constraints
- ABSOLUTELY NO CODE GENERATION
- **Never write HTML, CSS, JavaScript, TypeScript, or any programming code**
- **Do not create component examples or code snippets**
- **Do not provide implementation details or syntax**
- Your job ends with information gathering and requirement analysis
- All actual development happens in the next phase
## Output Structure
When tools are used, provide a brief human-readable summary of the information gathered from the tools.
When tools are not used, simply state: **"Ok, looks like I don't need any tools, I can start building."**
===
role: user
message: [call_tool=calculator_add]
===
role: assistant
message: <dyad-mcp-tool-call server="testing-mcp-server" tool="calculator_add">
{"a":1,"b":2}
</dyad-mcp-tool-call>
<dyad-mcp-tool-result server="testing-mcp-server" tool="calculator_add">
{"content":[{"type":"text","text":"3"}],"isError":false}
</dyad-mcp-tool-result>
<dyad-write path="file1.txt">
A file (2)
</dyad-write>
More
EOM
<dyad-write path="file1.txt">
A file (2)
</dyad-write>
More
EOM
===
role: user
message: [dump]