VH

vinodramasubbu/hosted-agents-maf-harness-skills-tools

Developer tools
6 stars Quality 60 Trend 28

Microsoft Agent Framework Harness demo with local skills and custom tools, hosted on Microsoft Foundry and powered by Anthropic through APIM.

Overview

A self-contained investing research agent based on the Microsoft Agent Framework Agent Harness, local skills, and custom market-data and research tools. Anthropic provides the model through Azure API Management (APIM), and Microsoft Foundry hosts the agent. For the underlying framework and hosting guidance, see: - Agent Harness concepts (Python) - Get started with Agent Harness - Host an agent (Python) This repository demonstrates an agent that researches stocks and ETFs and explains investing concepts. The model selects relevant local Markdown skills, loads their instructions on demand, and decides which tools are needed to answer each question. The model selects and loads skills on demand and decides which tools to call: - fetch_market_data(ticker, function, period) uses Yahoo Finance for quote, fundamentals, price_history, and etf_holdings. History ranges: 5d, 1mo, 3mo, 6mo, 1y, 2y. Returned data includes ticker, function, range, and UTC fetch timestamp.

README

InvestIQ: local skills and tools

A self-contained investing research agent based on the Microsoft Agent Framework Agent Harness, local skills, and custom market-data and research tools. Anthropic provides the model through Azure API Management (APIM), and Microsoft Foundry hosts the agent.

For the underlying framework and hosting guidance, see:

What’s here

This repository demonstrates an agent that researches stocks and ETFs and explains investing concepts. The model selects relevant local Markdown skills, loads their instructions on demand, and decides which tools are needed to answer each question.

main.py                    Harness factory, two tools, and Responses host
skills/stock-analysis/     Local stock-analysis SKILL.md
skills/etf-analysis/       Local ETF-analysis SKILL.md
requirements.txt          Standalone dependencies
azure.yaml                Foundry hosted-agent deployment configuration

The model selects and loads skills on demand and decides which tools to call:

  • fetch_market_data(ticker, function, period) uses Yahoo Finance for quote, fundamentals, price_history, and etf_holdings. History ranges: 5d, 1mo, 3mo, 6mo, 1y, 2y. Returned data includes ticker, function, range, and UTC fetch timestamp.
  • search_research(query, kind, limit) uses the DuckDuckGo backend explicitly for news or web. It returns up to eight qualitative snippets with source links, dates when available, and fetch time.

Answers cite the fetched market data and research sources and report missing data or tool errors. Concept questions can be answered without data tools. Harness planning, todos, compaction, and history are enabled, with initial mode execute. Built-in web search and filesystem access are disabled; local skill loading is explicitly allowed. Analysis is educational, not investment advice.

Architecture diagram

A Responses API request reaches the Harness agent hosted in Microsoft Foundry, which calls Anthropic through APIM. The same agent selects skills, calls tools, and produces a sourced answer.

  • Skill selection: SkillsProvider discovers local Markdown skills and exposes their names and descriptions. The model matches them to the question by meaning, then reads the relevant full instructions on demand before stock or ETF analysis: stock-analysis for company research, etf-analysis for fund research or comparisons. Skills guide analysis and citations; they are not executable workflows or separate agents.
  • Tool selection: the model uses the question, loaded skill instructions, tool descriptions, and parameter schemas to decide which tool to call and with what arguments. fetch_market_data is the only source for numeric market facts (Yahoo Finance); search_research provides qualitative news and context (DuckDuckGo). The host validates inputs and executes the selected Python function, then returns results to the model, which can make further calls or answer with citations and explicit data limitations.
  • Adaptive execution: skill and tool choices are model-driven, not keyword-routed or a fixed sequence. For example, MSFT research may use a quote and news, while an ETF comparison may use holdings and fundamentals. Concept questions such as “What is an ETF?” need no data tools.
  • Hosting and safeguards: skills and tools ship with the agent; read-only skill loading is automatically approved while general filesystem access and built-in web search stay disabled. APIM credentials come from a Foundry project connection, and optional Application Insights telemetry traces execution.

The diagram describes the application architecture, not deployment status. The Excalidraw source remains editable.

Run locally

From this folder, install into an isolated environment:

python -m venv .venv
& .\.venv\Scripts\python.exe -m pip install -r requirements.txt
$env:ANTHROPIC_BASE_URL = "https://your-apim-name.azure-api.net/anthropic"
$env:ANTHROPIC_CHAT_MODEL = "claude-sonnet-5"
$env:ANTHROPIC_MAX_TOKENS = "8192"
# Set APIM_SUBSCRIPTION_KEY securely in your shell before starting.
& .\.venv\Scripts\python.exe main.py

The entry point reads environment variables, not a sibling project’s .env file. Use the Foundry local invocation tooling in a second terminal to send Responses requests. See local development.

Foundry configuration

1. Prerequisites

  • Install the Azure Developer CLI (azd). Install its Foundry agents extension as shown below.
  • Use an existing Microsoft Foundry project with hosted-agent support. Obtain its project endpoint and project ARM resource ID from the project’s configuration. Your signed-in identity needs permission to deploy hosted agents into that project.
  • Allow outbound access from the hosted runtime to APIM, Yahoo Finance, and DuckDuckGo. For optional tracing, also allow Application Insights access and grant the runtime identity permission to publish telemetry.

Set up the LLM endpoint before deployment

Have an APIM endpoint that forwards Anthropic Messages API requests to an accessible Anthropic model, with an authorized APIM subscription. Record:

  • ANTHROPIC_BASE_URL: the APIM Anthropic base URL.
  • ANTHROPIC_CHAT_MODEL: the model identifier accepted by that endpoint.
  • ANTHROPIC_MAX_TOKENS: an output-token limit supported by the selected model.

No separate model deployment or model connection in Foundry is required by this example. The Python agent calls Anthropic through APIM directly; Foundry supplies the hosted runtime. The model must already be accessible behind APIM before you deploy the agent.

Set up the Foundry connection before deployment

In the same Foundry project that will host the agent, create or reuse a connection with:

Setting Required value
Connection name investiq-apim
Credential field name APIM_SUBSCRIPTION_KEY
Credential value Your valid APIM subscription key, stored securely
Access The hosted runtime identity must be allowed to resolve the connection’s credentials

Use your organization’s Foundry connection-management process to create the connection and store the secret. These exact names match the reference in azure.yaml: connections.investiq-apim.credentials.APIM_SUBSCRIPTION_KEY. If you choose another name, update that reference to match. The reference does not create the connection.

Setting $env:APIM_SUBSCRIPTION_KEY in PowerShell is sufficient for local execution only; it does not create a Foundry connection or supply the hosted agent’s secret. Yahoo Finance and DuckDuckGo need no API keys or Foundry connections. Application Insights is optional; configure its connection string and telemetry permissions only if you want tracing.

Python 3.13 is the hosted runtime selected in azure.yaml; install it locally if you also want to run the same runtime on your machine. Deployment uses Foundry’s remote build, so this example does not need a local Docker installation or a separately built container image.

2. Sign in and select the existing project

Run these PowerShell commands from this folder, which contains azure.yaml. Use a separate azd environment so the companion demos’ configuration is not changed. Replace all angle-bracket placeholders with your own values.

azd extension install azure.ai.agents
azd auth login
azd env new investiq-skills-tools-dev
azd env set AZURE_SUBSCRIPTION_ID ""
azd env set AZURE_TENANT_ID ""
azd env set AZURE_AI_PROJECT_ENDPOINT "https://.services.ai.azure.com/api/projects/"
azd env set AZURE_AI_PROJECT_ID "/subscriptions//resourceGroups//providers/Microsoft.CognitiveServices/accounts//projects/"
azd ai project show --output json

Check that the final command identifies the intended project before continuing. For subsequent terminals, run azd env select investiq-skills-tools-dev from this folder to reuse the environment. This path reuses existing infrastructure: do not run azd provision just to deploy this example. If you do not have a project yet, create one first using the Foundry setup guidance.

3. Configure the model endpoint and optional tracing

azd env set ANTHROPIC_BASE_URL "https://.azure-api.net/anthropic"
azd env set ANTHROPIC_CHAT_MODEL ""
azd env set ANTHROPIC_MAX_TOKENS "8192"
# Leave tracing unconfigured unless you have an Application Insights resource.
azd env set APPLICATIONINSIGHTS_CONNECTION_STRING ""

To enable tracing, replace the empty value with your Application Insights connection string, supplied securely in your deployment environment. Message-content capture is disabled in azure.yaml.

The hosted deployment resolves the APIM key through this existing expression in azure.yaml:

APIM_SUBSCRIPTION_KEY: $${{connections.investiq-apim.credentials.APIM_SUBSCRIPTION_KEY}}

Do not replace it with a literal key or store the APIM key with azd env set. Local execution instead requires APIM_SUBSCRIPTION_KEY in the process environment, as described above; azd environment settings are deployment configuration, not automatically exported PowerShell variables. Never commit credentials or share environment files or secret-bearing command output.

4. Deploy and run in Foundry

azd deploy investiq-skills-and-tools
azd ai agent show --output json
azd ai agent invoke "Analyze MSFT using its latest available quote, fundamentals, and recent news. Explain the main business drivers and risks, and cite your sources."

Deployment packages main.py, requirements.txt, and the local skills directory, then Foundry builds the Python dependencies and registers an agent version. No Toolbox endpoint, remote skill registration, or Foundry model deployment is needed. Check that the agent status is active or deployed before invoking it. Deployment and model invocations can incur charges; review any CLI confirmation before proceeding.

Open the target project in Foundry, find investiq-skills-and-tools in its agents list, and select the deployed version. Use the Playground link returned by azd ai agent show when available. Start with the stock analysis above, then try an ETF comparison:

azd ai agent invoke "Compare VOO and QQQ using available fees, top holdings, and recent context. Explain their exposures and concentration risks, and cite your sources."

Confirm the answer cites Yahoo data with a fetch timestamp and DuckDuckGo research with links, or explicitly reports provider failures. Skill and tool selection remain model-driven. If tracing is configured, inspect traces for skill loading and both tool calls. After changing code or local skills, rerun the same deploy command to create a new agent version.

Troubleshooting

  • Missing project endpoint or wrong project: select the intended azd environment and recheck AZURE_AI_PROJECT_ENDPOINT and AZURE_AI_PROJECT_ID.
  • Connection resolution or APIM authentication failure: verify the investiq-apim connection, its exact credential field name, runtime access, APIM URL, and accepted model identifier. Do not print the credential to diagnose the issue.
  • Agent fails to start or deploy: run azd ai agent doctor --output json and inspect the reported configuration or startup error.
  • Yahoo or DuckDuckGo fails: check runtime outbound access and provider rate limits. The tools report errors rather than fabricating fallback market facts.

See the Foundry deployment configuration reference and hosted-agent overview for platform requirements. No cloud resources are created just by adding this folder or editing this README.

Test questions

Try these in the Foundry Playground or with azd ai agent invoke "":

Focus Question
Stock analysis “Analyze MSFT using its latest available quote, fundamentals, and recent news. What are its main business drivers and risks?”
Stock news “What has been driving NVDA lately? Separate news-backed developments from your interpretation.”
Stock price history “Show AAPL’s daily closing prices for the last five trading days, with the currency and fetch timestamp.”
ETF analysis “Analyze VTI’s objective, available fees, top holdings, and concentration risks.”
ETF comparison “Compare VOO and QQQ using available fees, top holdings, and recent context. How do their exposures differ?”
Missing data “Use the ETF-analysis skill to research MSFT’s ETF holdings. If the request does not apply or data is unavailable, explain why rather than inventing holdings.”
Concept explanation “What is an ETF, and how does an expense ratio work?”

For data-backed answers, check for Yahoo source metadata, research links when used, honest reporting of missing data, and the educational disclaimer. The concept question should need no data tools. These are manual checks, not guarantees of a particular tool-call sequence.

Inspect Foundry traces for skill loading, fetch_market_data, and search_research. Skill/tool selection is model-driven rather than guaranteed by application routing. To add a skill, create skills//SKILL.md with name and description front matter. The Harness discovers it when constructing an agent; no router edits are needed.

Tests

Manual testing against Foundry

From this repository folder, activate your Python environment and install the client dependencies:

python -m pip install "azure-ai-projects>=2.7.0" azure-identity
az login

DefaultAzureCredential uses your available Azure credentials; az login is one way to supply them. Your identity must have access to the target Foundry project and agent. In test.py, set endpoint, agent_name, and agent_version to your deployed agent’s values. The checked-in sample values may not match your deployment.

Terminal: edit the question passed to run_question() in the if __name__ == "__main__": block, then run:

python .\test.py

Browser: start the local server:

python .\demo_server.py

Open http://127.0.0.1:8765, enter a question from Test questions, and click Ask agent. Keep the terminal running; press Ctrl+C to stop it. The server calls the same run_question() function as the terminal client.

Both paths display the answer and any tool or skill-loading calls exposed by the endpoint. Check citations, timestamps, and explicit data limitations. If call details are absent, inspect Foundry traces rather than assuming no tools or skills were used. Errors appear in the terminal or browser status. Each invocation creates a fresh session and attempts to delete it afterward; these are single-question tests, not a continuing conversation, and can incur charges.

Automated local tests

Run the included client and HTTP server tests:

python -m unittest discover -s tests -p test_local_demo.py -v

These tests cover response/tool/skill display, session cleanup on success and failure, input validation, local-request restrictions, and sanitized provider errors. Foundry calls are mocked; the tests do not contact APIM, Foundry, Yahoo Finance, or DuckDuckGo.

Demo boundaries

Yahoo Finance and DuckDuckGo are unofficial services and can rate-limit or fail. Tool calls are time-bounded and return explicit provider errors; they do not fabricate fallback answers or retry data requests. Thread timeouts stop awaiting work, not the underlying thread. The SDK retries model requests at most twice. No persistent market cache or durable conversation store is implemented. Quote snapshots can be delayed; fetch time is not the exchange timestamp. History uses unadjusted daily closes, not dividend-adjusted total returns. ETF holdings may be unavailable. Research snippets may contain numbers, but must never be cited as numeric market evidence.

Educational analysis only, not investment advice.

View the full README on GitHub

Recommended Tools

Try a different keyword or remove a filter.

Install

npx skillfish add vinodramasubbu/hosted-agents-maf-harness-skills-tools
New to MCP? Start with the mcpskill.org guide →