diff --git a/.gitignore b/.gitignore index 928ba0687..879a4f263 100644 --- a/.gitignore +++ b/.gitignore @@ -22,5 +22,5 @@ coverage/ a2a_agents/python/a2ui_agent/src/a2ui/assets/**/*.json ## new agent SDK path agent_sdks/python/src/a2ui/assets/**/*.json -## Generated JS file from the strictly-typed `sandbox.ts`. -samples/client/angular/projects/orchestrator/public/sandbox_iframe/sandbox.js +## Generated JS file from the strictly-typed `sandbox.ts`. +samples/client/angular/projects/mcp_calculator/public/sandbox_iframe/sandbox.js diff --git a/samples/agent/adk/orchestrator/README.md b/samples/agent/adk/orchestrator/README.md index 0b8b442b0..b0d79efc2 100644 --- a/samples/agent/adk/orchestrator/README.md +++ b/samples/agent/adk/orchestrator/README.md @@ -42,30 +42,17 @@ Subagents are configured using RemoteA2aAgent which translates ADK events to A2A uv run . --port=10005 ``` - Optionally, run the MCP Server and MCP App Proxy Agent to MCP Apps in A2UI demo: - - ```bash - cd samples/agent/mcp/calculator - uv run . --port=8000 - ``` - - ```bash - cd samples/agent/adk/mcp_app_proxy - uv run . --port=10006 - ``` - 3. Run the orchestrator agent: ```bash cd samples/agent/adk/orchestrator - uv run . --port=10002 --subagent_urls=http://localhost:10003 --subagent_urls=http://localhost:10004 --subagent_urls=http://localhost:10005 --subagent_urls=http://localhost:10006 + uv run . --port=10002 --subagent_urls=http://localhost:10003 --subagent_urls=http://localhost:10004 --subagent_urls=http://localhost:10005 ``` 4. Try commands that work with any agent: a. "Who is Alex Jordan?" (routed to contact lookup agent) b. "Show me chinese food restaurants in NYC" (routed to restaurant finder agent) c. "Show my sales data for Q4" (routed to rizzcharts) - d. "Open calculator" (routed to mcp app proxy) ## Disclaimer @@ -75,4 +62,4 @@ All operational data received from an external agent—including its AgentCard, Similarly, any UI definition or data stream received must be treated as untrusted. Malicious agents could attempt to spoof legitimate interfaces to deceive users (phishing), inject malicious scripts via property values (XSS), or generate excessive layout complexity to degrade client performance (DoS). If your application supports optional embedded content (such as iframes or web views), additional care must be taken to prevent exposure to malicious external sites. -Developer Responsibility: Failure to properly validate data and strictly sandbox rendered content can introduce severe vulnerabilities. Developers are responsible for implementing appropriate security measures—such as input sanitization, Content Security Policies (CSP), strict isolation for optional embedded content, and secure credential handling—to protect their systems and users. \ No newline at end of file +Developer Responsibility: Failure to properly validate data and strictly sandbox rendered content can introduce severe vulnerabilities. Developers are responsible for implementing appropriate security measures—such as input sanitization, Content Security Policies (CSP), strict isolation for optional embedded content, and secure credential handling—to protect their systems and users. diff --git a/samples/client/angular/README.md b/samples/client/angular/README.md index b68a240cd..9b3e3a273 100644 --- a/samples/client/angular/README.md +++ b/samples/client/angular/README.md @@ -37,6 +37,7 @@ Here are the instructions if you want to do each step manually. * `npm start -- contact` * `npm start -- rizzcharts` * `npm start -- orchestrator` + * `npm run build:sandbox && npm start -- mcp_calculator` * `npm start -- gallery` (Client-only, no server required) 5. Open http://localhost:4200/ diff --git a/samples/client/angular/angular.json b/samples/client/angular/angular.json index 87be99fb3..7044ec54d 100644 --- a/samples/client/angular/angular.json +++ b/samples/client/angular/angular.json @@ -495,6 +495,116 @@ } } } + }, + "mcp_calculator": { + "projectType": "application", + "schematics": { + "@schematics/angular:component": { + "style": "scss", + "skipTests": true + }, + "@schematics/angular:class": { + "skipTests": true + }, + "@schematics/angular:directive": { + "skipTests": true + }, + "@schematics/angular:guard": { + "skipTests": true + }, + "@schematics/angular:interceptor": { + "skipTests": true + }, + "@schematics/angular:pipe": { + "skipTests": true + }, + "@schematics/angular:resolver": { + "skipTests": true + }, + "@schematics/angular:service": { + "skipTests": true + } + }, + "root": "projects/mcp_calculator", + "sourceRoot": "projects/mcp_calculator/src", + "prefix": "app", + "architect": { + "build": { + "builder": "@angular/build:application", + "options": { + "browser": "projects/mcp_calculator/src/main.ts", + "tsConfig": "projects/mcp_calculator/tsconfig.app.json", + "preserveSymlinks": true, + "inlineStyleLanguage": "scss", + "assets": [ + { + "glob": "**/*", + "input": "projects/mcp_calculator/public" + } + ], + "styles": [ + "projects/mcp_calculator/src/styles.scss" + ], + "server": "projects/mcp_calculator/src/main.server.ts", + "outputMode": "server", + "ssr": { + "entry": "projects/mcp_calculator/src/server.ts" + } + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500KB", + "maximumError": "1MB" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "4kB", + "maximumError": "8kB" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "builder": "@angular/build:dev-server", + "configurations": { + "production": { + "buildTarget": "mcp_calculator:build:production" + }, + "development": { + "buildTarget": "mcp_calculator:build:development" + } + }, + "defaultConfiguration": "development" + }, + "test": { + "builder": "@angular/build:karma", + "options": { + "codeCoverage": true, + "tsConfig": "projects/mcp_calculator/tsconfig.spec.json", + "inlineStyleLanguage": "scss", + "assets": [ + { + "glob": "**/*", + "input": "projects/mcp_calculator/public" + } + ], + "styles": [ + "projects/mcp_calculator/src/styles.scss" + ] + } + } + } } }, "cli": { diff --git a/samples/client/angular/package.json b/samples/client/angular/package.json index c17b2d97c..db5af3a29 100644 --- a/samples/client/angular/package.json +++ b/samples/client/angular/package.json @@ -14,11 +14,7 @@ "build:renderer": "cd ../../../renderers && for dir in 'web_core' 'markdown/markdown-it'; do (cd \"$dir\" && npm install && npm run build); done", "serve:agent:restaurant": "cd ../../agent/adk/restaurant_finder && uv run .", "demo:restaurant": "npm run build:renderer && concurrently -k -n \"AGENT,WEB\" -c \"magenta,blue\" \"npm run serve:agent:restaurant\" \"npm start -- restaurant\"", - "serve:agent:contact": "cd ../../agent/adk/contact_lookup && uv run .", - "demo:contact": "npm run build:renderer && concurrently -k -n \"AGENT,WEB\" -c \"magenta,blue\" \"npm run serve:agent:contact\" \"npm start -- contact\"", - "serve:agent:rizzcharts": "cd ../../agent/adk/rizzcharts && uv run .", - "demo:rizzcharts": "npm run build:renderer && concurrently -k -n \"AGENT,WEB\" -c \"magenta,blue\" \"npm run serve:agent:rizzcharts\" \"npm start -- rizzcharts\"", - "build:sandbox": "esbuild projects/orchestrator/public/sandbox_iframe/sandbox.ts --bundle --outfile=projects/orchestrator/public/sandbox_iframe/sandbox.js --format=esm --platform=browser" + "build:sandbox": "esbuild projects/mcp_calculator/public/sandbox_iframe/sandbox.ts --bundle --outfile=projects/mcp_calculator/public/sandbox_iframe/sandbox.js --format=esm --platform=browser" }, "prettier": { "printWidth": 100, @@ -93,4 +89,4 @@ "../../../renderers/web_core", "../../../renderers/markdown/markdown-it" ] -} \ No newline at end of file +} diff --git a/samples/client/angular/projects/mcp_calculator/README.md b/samples/client/angular/projects/mcp_calculator/README.md new file mode 100644 index 000000000..25e0c7ea5 --- /dev/null +++ b/samples/client/angular/projects/mcp_calculator/README.md @@ -0,0 +1,23 @@ +# MCP Calculator + +Sample application using the Chat-Canvas component with MCP Calculator Agent. + +## Prerequisites + +1. [nodejs](https://nodejs.org/en) +2. An endpoint hosting the MCP Calculator A2AService. ([Review the instructions on how to run MCP Calculator A2AService](../../../../agent/adk/mcp_app_proxy/README.md).) + +## Running + +1. Build the shared dependencies by running `npm run build` in the `renderers/web_core` directory +2. Install the dependencies: `npm i` +3. Run the A2A server for all of the agents. ([Link to instructions](../../../../agent/adk/mcp_app_proxy/README.md)) +4. Build the `sandbox.js` for testing MCP Apps in A2UI demo + +- `npm run build:sandbox` + +5. Run the app: + +- `npm start -- mcp_calculator` + +6. Open http://localhost:4200/ diff --git a/samples/client/angular/projects/mcp_calculator/public/favicon.ico b/samples/client/angular/projects/mcp_calculator/public/favicon.ico new file mode 100644 index 000000000..57614f9c9 Binary files /dev/null and b/samples/client/angular/projects/mcp_calculator/public/favicon.ico differ diff --git a/samples/client/angular/projects/mcp_calculator/public/gemini-color.svg b/samples/client/angular/projects/mcp_calculator/public/gemini-color.svg new file mode 100644 index 000000000..f1cf35757 --- /dev/null +++ b/samples/client/angular/projects/mcp_calculator/public/gemini-color.svg @@ -0,0 +1 @@ +Gemini \ No newline at end of file diff --git a/samples/client/angular/projects/orchestrator/public/sandbox_iframe/README.md b/samples/client/angular/projects/mcp_calculator/public/sandbox_iframe/README.md similarity index 90% rename from samples/client/angular/projects/orchestrator/public/sandbox_iframe/README.md rename to samples/client/angular/projects/mcp_calculator/public/sandbox_iframe/README.md index 71a93370b..f2e2f98c6 100644 --- a/samples/client/angular/projects/orchestrator/public/sandbox_iframe/README.md +++ b/samples/client/angular/projects/mcp_calculator/public/sandbox_iframe/README.md @@ -6,7 +6,7 @@ This directory contains the `sandbox.html` and its associated resources. `sandbox.html` is designed to be loaded into an `