feat(nodejs): Add Google ADK sample agent with Microsoft OpenTelemetry distro#313
Open
Yogeshp-MSFT wants to merge 1 commit into
Open
feat(nodejs): Add Google ADK sample agent with Microsoft OpenTelemetry distro#313Yogeshp-MSFT wants to merge 1 commit into
Yogeshp-MSFT wants to merge 1 commit into
Conversation
…y distro Adds a Node.js/TypeScript sample using Google ADK (Agent Development Kit) with Gemini models, integrated with Microsoft Agent 365 SDK for hosting, MCP tooling, notifications, and @microsoft/opentelemetry for observability.
Contributor
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds a complete Node.js “Google ADK + Microsoft Agent 365 SDK” sample agent, including hosting, MCP tool registration, and OpenTelemetry instrumentation, along with local/Playground configuration and documentation.
Changes:
- Introduces a TypeScript/Node.js sample agent app (Express entrypoint, hosting handlers, Google ADK agent implementation).
- Adds MCP tool-server discovery/registration against the A365 tooling gateway.
- Adds observability bootstrapping (Microsoft OpenTelemetry distro), VS Code launch/tasks, and setup docs/env templates.
Reviewed changes
Copilot reviewed 20 out of 20 changed files in this pull request and generated 13 comments.
Show a summary per file
| File | Description |
|---|---|
| nodejs/google-adk/sample-agent/package.json | Defines runtime + dev dependencies and scripts for building/running the sample. |
| nodejs/google-adk/sample-agent/tsconfig.json | TypeScript compilation settings for producing dist output and typings. |
| nodejs/google-adk/sample-agent/index.ts | Express entrypoint with health endpoints + JWT middleware + adapter routing. |
| nodejs/google-adk/sample-agent/instrumentation.ts | OpenTelemetry initialization and exporter debugging patch. |
| nodejs/google-adk/sample-agent/agent.ts | Google ADK agent runner, MCP tool initialization, and InferenceScope telemetry. |
| nodejs/google-adk/sample-agent/mcpToolRegistrationService.ts | A365 gateway call to list MCP servers and register MCPToolset instances. |
| nodejs/google-adk/sample-agent/hosting.ts | AgentApplication set up, message handling, typing loop, and notifications. |
| nodejs/google-adk/sample-agent/README.md | End-user documentation for running/testing and feature overview. |
| nodejs/google-adk/sample-agent/.env.example | Environment variable template for local/dev/prod scenarios. |
| nodejs/google-adk/sample-agent/m365agents*.yml | Agents Toolkit / Playground configuration files. |
| nodejs/google-adk/sample-agent/.vscode/* | Debug + task automation for running locally / Playground. |
| import type { TurnContext } from '@microsoft/agents-hosting'; | ||
|
|
||
| // Use axios directly to call the gateway (same as the SDK uses internally) | ||
| import axios from 'axios'; |
Comment on lines
+7
to
+10
| McpToolServerConfigurationService, | ||
| ToolingConfiguration, | ||
| resolveTokenScopeForServer, | ||
| } from '@microsoft/agents-a365-tooling'; |
Comment on lines
+36
to
+40
| private configService: McpToolServerConfigurationService; | ||
|
|
||
| constructor() { | ||
| this.configService = new McpToolServerConfigurationService(); | ||
| } |
Comment on lines
+119
to
+125
| logger.error(`Failed to list MCP tool servers:`); | ||
| logger.error(` agenticAppId: '${agenticAppId}'`); | ||
| logger.error(` Error: ${err.message}`); | ||
| if (err.response) { | ||
| logger.error(` HTTP Status: ${err.response.status}`); | ||
| logger.error(` Response data: ${JSON.stringify(err.response.data)}`); | ||
| } |
Comment on lines
+31
to
+37
| proto.postWithRetries = async function (url: string, body: Uint8Array, headers: Record<string, string>) { | ||
| const originalFetch = globalThis.fetch; | ||
| let attempt = 0; | ||
| const self = this; | ||
| globalThis.fetch = async (input: any, init?: any) => { | ||
| attempt++; | ||
| const response: Response = await originalFetch(input, init); |
Comment on lines
+100
to
+107
| // Inject display name into agent instruction (personalized per turn — local only, no instance mutation) | ||
| const personalizedInstruction = getPersonalizedInstruction(displayName); | ||
| const personalizedAgent = new Agent({ | ||
| name: this.agentName, | ||
| model: this.model, | ||
| description: this.description, | ||
| instruction: personalizedInstruction, | ||
| }); |
Comment on lines
+179
to
+186
| // Build baggage from TurnContext — auto-populates tenant, agent, channel, conversation | ||
| const baggageScope = BaggageBuilderUtils.fromTurnContext( | ||
| new BaggageBuilder(), | ||
| context as any | ||
| ).build(); | ||
|
|
||
| return new Promise<string>((resolve, reject) => { | ||
| baggageScope.run(async () => { |
Comment on lines
+201
to
+204
| scope.dispose(); | ||
| } | ||
| }); | ||
| }); |
Comment on lines
+254
to
+256
| const timeoutPromise = new Promise<Agent>((_, reject) => | ||
| setTimeout(() => reject(new Error('MCP tool initialization timed out')), 10_000) | ||
| ); |
| authToken: bearerToken || undefined, | ||
| }); | ||
|
|
||
| return await Promise.race([initPromise, timeoutPromise]); |
Author
|
Hi @gwharris7 can you review this pr? |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a new Node.js sample agent using Google ADK (Agent Development Kit) with Gemini models (Vertex AI / public API), fully integrated with the Microsoft Agent 365 SDK, MCP tooling, notifications, and the
@microsoft/opentelemetrydistro for observability.This is the first Google ADK sample in the Node.js samples collection.
What's included
@google/adkv1.1.0 withRunner.runEphemeral(),InMemorySessionService, andMCPToolset(StreamableHTTP transport)/agents/v2/{agenticAppId}/mcpServerswith OBO token exchange usingToolingConfiguration.mcpPlatformAuthenticationScope@microsoft/opentelemetryv1.0.2 withAgenticTokenCacheInstance.refreshObservabilityToken(),BaggageBuilderUtils.fromTurnContext(),InferenceScope, and A365 exporter response loggingonAgentNotification("agents:*")handling for email (createEmailResponseActivity), Word comments (WpxComment), and lifecycle eventsauthorization: { agentic: { type: 'agentic' } }inAgentApplication,authorizeJWT(loadAuthConfigFromEnv())on Express,CloudAdapter(getAuthConfigWithDefaults())setIntervaltyping loop (~4s), final LLM responseactivity.from.nameinto agent system prompt per turnm365agents.yml, m365agents.playground.yml,.vscode/launch.json,env/.env.playgroundFile structure
Key design decisions
McpToolServerConfigurationService.listToolServers(){ mcpServers: [...] }— handles both shapesMCPToolset({ type: 'StreamableHTTPConnectionParams', header: {...} })connectionParams.type;header(singular) notheadersconfigDotenv()in instrumentation.ts before@microsoft/opentelemetryimportA365_OBSERVABILITY_LOG_LEVELmust be inprocess.envwhen the logging module initializesAgent365Exporter.postWithRetriespatch for response body loggingTurnContextonly — noAGENTIC_APP_IDenv fallbackactivity.recipient.agenticAppIdat runtimeTest plan
npx tsc --noEmit— zero errorsnpm run dev— server starts, health endpoint returns 200mcp_MailToolsdiscovered,SendEmailWithAttachmentsfunction call executed by GeminiInferenceScopespans emitted,BaggageBuilderauto-populated, A365 exporter HTTP 200 withrejectedSpans: 0, all sinks (flashpoint/sentinel/esp) statussentinstallationUpdateactivity...animation refreshes during LLM processingDependencies
@google/adk@microsoft/agents-hosting@microsoft/agents-activity@microsoft/agents-a365-notifications@microsoft/agents-a365-tooling@microsoft/opentelemetryexpressdotenv