diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 885deb4..789511f 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -8,8 +8,9 @@ Read [AGENTS.md](../AGENTS.md) and [docs/architecture.md](../docs/architecture.m ## MCP -- Server: `mcp-server.js` — registered in `.vscode/mcp.json` +- Server: `mcp-server.js` — VS Code: `.vscode/mcp.json` · CLI: `.mcp.json` - Invoke in Copilot Chat: `@agrivalue-iq get_market_intelligence crop="Olive Oil"` +- Copilot CLI: run `copilot` from repo root → `/mcp show agrivalue-iq` — see [docs/COPILOT_CLI.md](../docs/COPILOT_CLI.md) - Tools: `get_market_intelligence`, `generate_supply_contract`, `evaluate_crop_quality` ## Code patterns diff --git a/.mcp.json b/.mcp.json new file mode 100644 index 0000000..ddfb0bf --- /dev/null +++ b/.mcp.json @@ -0,0 +1,11 @@ +{ + "mcpServers": { + "agrivalue-iq": { + "type": "stdio", + "command": "node", + "args": ["scripts/mcp-launcher.mjs"], + "env": {}, + "tools": ["*"] + } + } +} diff --git a/AGENTS.md b/AGENTS.md index eb0f27d..bd311fd 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -10,7 +10,7 @@ Sicilian value-chain optimizer for **Agents League Battle #1** (Creative Apps + | IQ data | `lib/iq-data.js` | Unified Fabric / portfolio / optimize / advisor | | Fabric graph | `lib/fabric-iq.js`, `lib/fabric-lakehouse.js` | Semantic market graph (+ SQL fallback) | | Work IQ | `lib/work-iq.js` | Microsoft Graph / Teams webhooks | -| MCP | `mcp-server.js`, `.vscode/mcp.json` | Copilot tools in VS Code | +| MCP | `mcp-server.js`, `.vscode/mcp.json`, `.mcp.json` | Copilot tools in VS Code + Copilot CLI | | UI | `public/index.html`, `public/demo.html`, `public/js/app.js` | Terminal + judge teleprompter | | Static sync | `scripts/sync-static-data.js` | Copies `lib/fabric-iq.js` → `public/js/fabric-iq-client.js` | @@ -22,6 +22,7 @@ Sicilian value-chain optimizer for **Agents League Battle #1** (Creative Apps + npm install npm start # http://localhost:3000 npm run mcp # MCP server (stdio) +npm run verify:mcp # smoke-test MCP startup npm test # node:test suite npm run lint # ESLint npm run agent:action -- help # deterministic demo actions @@ -33,6 +34,7 @@ npm run build:static # Pages build (sync + config inject) - [docs/architecture.md](docs/architecture.md) — system overview - [docs/MICROSOFT_IQ.md](docs/MICROSOFT_IQ.md) — Fabric / Foundry / Work IQ - [docs/COPILOT.md](docs/COPILOT.md) — Copilot + MCP usage +- [docs/COPILOT_CLI.md](docs/COPILOT_CLI.md) — Copilot CLI + `.mcp.json` - [docs/AZURE_DEPLOY.md](docs/AZURE_DEPLOY.md) — Azure App Service + Pages - [.agents/skills/agrivalue-iq-operator/SKILL.md](.agents/skills/agrivalue-iq-operator/SKILL.md) — operator skill diff --git a/README.md b/README.md index 9fbb58c..39b0c2b 100644 --- a/README.md +++ b/README.md @@ -37,11 +37,12 @@ npm install cp .env.example .env # optional: Azure, Fabric, Graph credentials npm start # http://localhost:3000 npm run mcp # Copilot MCP server for VS Code +npm run verify:mcp # smoke-test MCP (no CLI required) npm test # node:test suite (Fabric IQ + agent memory) npm run lint # ESLint ``` -**AI / agent context:** [AGENTS.md](AGENTS.md) · [docs/architecture.md](docs/architecture.md) · [.github/copilot-instructions.md](.github/copilot-instructions.md) +**AI / agent context:** [AGENTS.md](AGENTS.md) · [docs/architecture.md](docs/architecture.md) · [docs/COPILOT_CLI.md](docs/COPILOT_CLI.md) · [.github/copilot-instructions.md](.github/copilot-instructions.md) ### Test Locally Or In Codespaces @@ -100,12 +101,12 @@ npm run agent:action -- contract --crop "Olive Oil" --qty 15 --buyer "Cooperativ ## Challenge Requirements -| Requirement | Status | Documentation | -| --------------------- | --------------------------------------- | -------------------------------------------- | -| GitHub Copilot + MCP | Done | [docs/COPILOT.md](docs/COPILOT.md) | -| Microsoft IQ (×3) | Demo + docs | [docs/MICROSOFT_IQ.md](docs/MICROSOFT_IQ.md) | -| Azure deployment | Workflow ready | [docs/AZURE_DEPLOY.md](docs/AZURE_DEPLOY.md) | -| Submission demo video | [YouTube](https://youtu.be/o8KqG8foLfM) | [docs/DEMO_SCRIPT.md](docs/DEMO_SCRIPT.md) | +| Requirement | Status | Documentation | +| --------------------- | --------------------------------------- | ------------------------------------------------------------------------------- | +| GitHub Copilot + MCP | Done | [docs/COPILOT.md](docs/COPILOT.md) · [docs/COPILOT_CLI.md](docs/COPILOT_CLI.md) | +| Microsoft IQ (×3) | Demo + docs | [docs/MICROSOFT_IQ.md](docs/MICROSOFT_IQ.md) | +| Azure deployment | Workflow ready | [docs/AZURE_DEPLOY.md](docs/AZURE_DEPLOY.md) | +| Submission demo video | [YouTube](https://youtu.be/o8KqG8foLfM) | [docs/DEMO_SCRIPT.md](docs/DEMO_SCRIPT.md) | ## UI Features (v3) diff --git a/docs/COPILOT.md b/docs/COPILOT.md index 1407a3f..5233a81 100644 --- a/docs/COPILOT.md +++ b/docs/COPILOT.md @@ -69,6 +69,17 @@ When the market chart threw `getElementById('trendChart')` errors, Copilot Chat 3. Run `npm install` then verify: `npm run mcp` (should log "running on stdio") 4. In Copilot Chat, reference tools with `@agrivalue-iq` +## Copilot CLI (terminal) + +Same MCP server works in **GitHub Copilot CLI** via repo-root [`.mcp.json`](../.mcp.json). + +```bash +npm run verify:mcp # smoke test before push +copilot # from repo root → /mcp show agrivalue-iq +``` + +Full setup, test steps, and example prompts: **[docs/COPILOT_CLI.md](COPILOT_CLI.md)** + ## Suggested Copilot Workflows for Judges ### Write a contract from live optimization results diff --git a/docs/COPILOT_CLI.md b/docs/COPILOT_CLI.md new file mode 100644 index 0000000..6e960ee --- /dev/null +++ b/docs/COPILOT_CLI.md @@ -0,0 +1,251 @@ +# GitHub Copilot CLI — AgriValue MCP + +Use **GitHub Copilot CLI** in the terminal with the same `agrivalue-iq` MCP server as VS Code — no duplicate logic, same three tools: + +| Tool | Purpose | +| -------------------------- | -------------------------------- | +| `get_market_intelligence` | Fabric IQ pricing + compliance | +| `generate_supply_contract` | Fair-Trade contract draft | +| `evaluate_crop_quality` | Vision grade + profit multiplier | + +## Prerequisites + +1. [GitHub Copilot subscription](https://github.com/features/copilot/plans) (Free tier works with limits) +2. [Copilot CLI installed](https://docs.github.com/en/copilot/how-tos/copilot-cli/install-copilot-cli) +3. This repo cloned and dependencies installed: + +```bash +git clone https://github.com/cdm227/AgriValue-Tracker.git +cd AgriValue-Tracker +npm install +``` + +## How it works + +``` +Terminal (copilot CLI) → .mcp.json → mcp-server.js → lib/iq-data.js +VS Code Copilot Chat → .vscode/mcp.json → (same server) +``` + +Repo-root **`.mcp.json`** is loaded automatically when you run Copilot CLI inside this project. + +--- + +## Test locally (before you push) + +### Step 1 — MCP smoke test (no Copilot CLI needed) + +From the repo root: + +```bash +npm run verify:mcp +``` + +Expected output: + +```text +OK: AgriValue MCP server started (Fabric IQ synced) +``` + +Also confirm VS Code config still works: + +```bash +npm run mcp +``` + +You should see on stderr: `AgriValue MCP Server running on stdio (Fabric IQ synced)` — press `Ctrl+C` to stop. + +### Step 2 — Install Copilot CLI + +Follow the official guide: [Install Copilot CLI](https://docs.github.com/en/copilot/how-tos/copilot-cli/install-copilot-cli) + +Quick check: + +```bash +copilot --version +``` + +Sign in if prompted (`copilot auth` or follow CLI prompts). + +### Step 3 — Start CLI in this repo + +**Important:** run Copilot CLI from the **repository root** so `.mcp.json` is picked up. + +```bash +cd AgriValue-Tracker +copilot +``` + +### Step 4 — Verify MCP is loaded + +Inside the interactive CLI: + +```text +/mcp show +``` + +You should see **`agrivalue-iq`** listed. + +Details and tools: + +```text +/mcp show agrivalue-iq +``` + +Expect three tools: `get_market_intelligence`, `generate_supply_contract`, `evaluate_crop_quality`. + +If the server is missing: + +```text +/mcp reload +/mcp show +``` + +Or add manually (same as `.mcp.json`): + +```text +/mcp add +``` + +- **Server Name:** `agrivalue-iq` +- **Type:** Local / STDIO +- **Command:** `node mcp-server.js` +- **Tools:** `*` + +### Step 5 — Run a grounded prompt + +In Copilot CLI (interactive): + +```text +Use the agrivalue-iq MCP tools to get market intelligence for Olive Oil, then generate a Fair-Trade supply contract for 15 metric tons, organic/DOP enabled, buyer "Cooperativa Valle del Belice". Summarize Path A vs Path B added value. +``` + +One-shot from the shell (non-interactive): + +```bash +copilot -p "Use agrivalue-iq get_market_intelligence for Olive Oil and generate_supply_contract for 15 tons organic with buyer Cooperativa Valle del Belice" +``` + +Exact flags depend on your CLI version — run `copilot --help` if `-p` differs. + +### Step 6 — Match the web app workflow + +1. Open `http://localhost:3000` (or [GitHub Pages demo](https://cdm227.github.io/AgriValue-Tracker)) +2. Run **IQ Pipeline** → Olive Oil, 15 MT, organic +3. Click **Copy for Copilot MCP** in the UI +4. Paste the prompt into **Copilot CLI** instead of VS Code Chat + +Same MCP tools, terminal instead of IDE. + +--- + +## User guide (judges & contributors) + +### VS Code vs CLI + +| Surface | Config file | When to use | +| --------------- | ----------------------- | -------------------------------------------- | +| **VS Code** | `.vscode/mcp.json` | IDE workflow, demo video cut to Copilot Chat | +| **Copilot CLI** | `.mcp.json` (repo root) | Terminal, automation, headless dev | + +Both call **`scripts/mcp-launcher.mjs`** → **`mcp-server.js`** → **`lib/iq-data.js`**. + +The launcher sets the repo root as cwd so Copilot CLI can connect reliably. + +### Example prompts + +**Market intel:** + +```text +@agrivalue-iq get_market_intelligence crop="Grapes" +``` + +**Contract (after optimization):** + +```text +@agrivalue-iq generate_supply_contract crop="Olive Oil" qtyTons=15 isOrganic=true buyer="Cooperativa Valle del Belice" + +Add a force majeure clause for Sicilian harvest weather. +``` + +**Quality before optimize:** + +```text +@agrivalue-iq evaluate_crop_quality crop="Olive Oil" +``` + +### MCP management commands + +| Command | Action | +| --------------------------- | -------------------------- | +| `/mcp show` | List all MCP servers | +| `/mcp show agrivalue-iq` | Tools for this repo | +| `/mcp reload` | Reload after config change | +| `/mcp disable agrivalue-iq` | Turn off for session | +| `/mcp enable agrivalue-iq` | Turn back on | + +### Troubleshooting + +#### `Failed to connect to MCP server "agrivalue-iq"` + +1. **Run from repo root** (where `.mcp.json` lives): + + ```bash + cd /mnt/c/Users/calog/AgriValue-Tracker # your clone path + ls -la .mcp.json # must exist (use ls -a for dotfiles) + ``` + +2. **Smoke test without Copilot CLI:** + + ```bash + npm install + npm run verify:mcp + npm run mcp:cli # should log: AgriValue MCP Server running on stdio — Ctrl+C to stop + ``` + +3. **Reload MCP in Copilot CLI:** + + ```text + /mcp reload + /mcp show agrivalue-iq + ``` + +4. **Trust the folder** — on first launch Copilot CLI may ask to trust the workspace; MCP from `.mcp.json` loads only after trust. + +5. **WSL vs Windows** — run Copilot CLI in the **same environment** as Node: + - WSL: `which node` and `copilot` both inside WSL + - Windows: use PowerShell/CMD, not WSL `/mnt/c/...` mixed with Windows `copilot.exe` + +6. **Manual add** (if `.mcp.json` is not picked up): + + ```text + /mcp add + ``` + + - Name: `agrivalue-iq` + - Type: **STDIO** + - Command: `node scripts/mcp-launcher.mjs` + - Tools: `*` + + Or edit `~/.copilot/mcp-config.json` with the same entry (use absolute path to `scripts/mcp-launcher.mjs` if needed). + +7. **Fabric SQL in `.env`** — if `FABRIC_SQL_*` is set but unreachable, the server still starts (sync runs in background). Remove or fix `.env` if startup is slow. + +| Problem | Fix | +| --------------------------------- | ------------------------------------------------------ | +| `agrivalue-iq` not in `/mcp show` | Run CLI from repo root; `ls -la .mcp.json` | +| MCP server fails to start | `npm run verify:mcp` and `npm run mcp:cli` | +| Wrong crop / empty tools | Crops: Olive Oil, Grapes, Wheat, Coffee, Milk | +| Plain `ls` hides config | Use `ls -a` to see `.mcp.json`, `.gitattributes`, etc. | + +### No secrets required + +MCP uses in-memory Fabric IQ demo data by default. Azure/Fabric env vars in `.env` are optional — same as the web app. + +--- + +## Related docs + +- [COPILOT.md](COPILOT.md) — VS Code + how Copilot built the project +- [MICROSOFT_IQ.md](MICROSOFT_IQ.md) — Fabric / Foundry / Work IQ +- [DEMO_SCRIPT.md](DEMO_SCRIPT.md) — 2-min judge video script diff --git a/docs/architecture.md b/docs/architecture.md index c1b22cf..79ea624 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -24,16 +24,16 @@ AgriValue Tracker connects a static GitHub Pages UI to an optional Azure Node.js ## Layers -| Layer | Module | Responsibility | -| ------------ | --------------------------------------------- | ----------------------------------------- | -| Presentation | `public/index.html`, `public/js/app.js` | Terminal UI, charts, advisor, vision scan | -| Judge demo | `public/demo.html` | 2-min teleprompter + embedded live app | -| API | `server.js` | REST routes, CORS, Foundry agent polling | -| Domain | `lib/iq-data.js` | Portfolio, optimize, advisor, contracts | -| Fabric IQ | `lib/fabric-iq.js`, `lib/fabric-lakehouse.js` | Crop → processor graph, Path A vs B | -| Agent memory | `lib/agent-memory.js` | In-session trade history | -| Work IQ | `lib/work-iq.js` | Teams via Graph or webhook | -| MCP | `mcp-server.js` | Copilot tool surface | +| Layer | Module | Responsibility | +| ------------ | ------------------------------------------------ | ----------------------------------------- | +| Presentation | `public/index.html`, `public/js/app.js` | Terminal UI, charts, advisor, vision scan | +| Judge demo | `public/demo.html` | 2-min teleprompter + embedded live app | +| API | `server.js` | REST routes, CORS, Foundry agent polling | +| Domain | `lib/iq-data.js` | Portfolio, optimize, advisor, contracts | +| Fabric IQ | `lib/fabric-iq.js`, `lib/fabric-lakehouse.js` | Crop → processor graph, Path A vs B | +| Agent memory | `lib/agent-memory.js` | In-session trade history | +| Work IQ | `lib/work-iq.js` | Teams via Graph or webhook | +| MCP | `mcp-server.js`, `.vscode/mcp.json`, `.mcp.json` | Copilot tool surface (VS Code + CLI) | ## Key flows @@ -61,4 +61,5 @@ When `public/config.js` has `staticFallback: true`, the browser uses `public/moc - [MICROSOFT_IQ.md](MICROSOFT_IQ.md) — IQ integration detail - [AZURE_DEPLOY.md](AZURE_DEPLOY.md) — provisioning and env vars - [COPILOT.md](COPILOT.md) — Copilot development story +- [COPILOT_CLI.md](COPILOT_CLI.md) — Copilot CLI terminal workflow - [adr/001-triple-iq-stack.md](adr/001-triple-iq-stack.md) — ADR: why three IQ layers diff --git a/mcp-server.js b/mcp-server.js index d643f9a..6d33b6c 100644 --- a/mcp-server.js +++ b/mcp-server.js @@ -1,13 +1,17 @@ import { Server } from "@modelcontextprotocol/sdk/server/index.js"; import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; import { CallToolRequestSchema, ListToolsRequestSchema } from "@modelcontextprotocol/sdk/types.js"; +import { fileURLToPath } from "node:url"; +import { dirname } from "node:path"; +import { chdir } from "node:process"; import { CROP_NAMES, getMarketIntelligence, generateSupplyContract, evaluateQuality, - syncFabricGraph, -} from "./lib/iq-data.js"; +} from "./lib/fabric-iq.js"; + +chdir(dirname(fileURLToPath(import.meta.url))); const server = new Server( { name: "agrivalue-iq-mcp", version: "1.1.0" }, @@ -102,10 +106,9 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => { }); async function main() { - await syncFabricGraph(true); const transport = new StdioServerTransport(); await server.connect(transport); - console.error("AgriValue MCP Server running on stdio (Fabric IQ synced)"); + console.error("AgriValue MCP Server running on stdio"); } main().catch(console.error); diff --git a/package.json b/package.json index dc54e97..90f07af 100644 --- a/package.json +++ b/package.json @@ -7,6 +7,8 @@ "scripts": { "start": "node server.js", "mcp": "node mcp-server.js", + "mcp:cli": "node scripts/mcp-launcher.mjs", + "verify:mcp": "node scripts/verify-mcp.mjs", "agent:action": "node scripts/agent-action.mjs", "build:static": "node scripts/sync-static-data.js && node scripts/inject-config.js", "prestart": "node scripts/sync-static-data.js", diff --git a/scripts/mcp-launcher.mjs b/scripts/mcp-launcher.mjs new file mode 100644 index 0000000..e353be9 --- /dev/null +++ b/scripts/mcp-launcher.mjs @@ -0,0 +1,27 @@ +#!/usr/bin/env node +/** + * Copilot CLI / MCP launcher — always runs mcp-server.js from repo root + * (fixes "Failed to connect" when CLI cwd is not the project directory). + */ +import { spawn } from "node:child_process"; +import { fileURLToPath } from "node:url"; +import { dirname, join } from "node:path"; + +const repoRoot = join(dirname(fileURLToPath(import.meta.url)), ".."); +const serverEntry = join(repoRoot, "mcp-server.js"); + +const child = spawn(process.execPath, [serverEntry], { + cwd: repoRoot, + stdio: "inherit", + env: { ...process.env, AGRIVALUE_MCP: "1" }, +}); + +child.on("exit", (code, signal) => { + if (signal) process.kill(process.pid, signal); + process.exit(code ?? 1); +}); + +child.on("error", (err) => { + console.error("AgriValue MCP launcher failed:", err.message); + process.exit(1); +}); diff --git a/scripts/verify-mcp.mjs b/scripts/verify-mcp.mjs new file mode 100644 index 0000000..8cf8b9c --- /dev/null +++ b/scripts/verify-mcp.mjs @@ -0,0 +1,69 @@ +/** + * Smoke-test MCP server startup (no Copilot CLI required). + * Run: npm run verify:mcp + */ +import { readFileSync, existsSync } from "node:fs"; +import { spawn } from "node:child_process"; +import { fileURLToPath } from "node:url"; +import { dirname, join } from "node:path"; + +const repoRoot = join(dirname(fileURLToPath(import.meta.url)), ".."); +const cfg = JSON.parse(readFileSync(join(repoRoot, ".mcp.json"), "utf8")); +const server = cfg.mcpServers?.["agrivalue-iq"]; + +if (!server) { + console.error("FAIL: .mcp.json missing mcpServers.agrivalue-iq"); + process.exit(1); +} + +const launcherPath = join(repoRoot, "scripts", "mcp-launcher.mjs"); +if (!existsSync(launcherPath)) { + console.error("FAIL: scripts/mcp-launcher.mjs not found"); + process.exit(1); +} + +// Test mcp-server.js directly (launcher uses stdio:inherit — not capturable here). +const proc = spawn(process.execPath, [join(repoRoot, "mcp-server.js")], { + stdio: ["ignore", "pipe", "pipe"], + cwd: repoRoot, + env: { ...process.env, AGRIVALUE_MCP: "1" }, +}); + +let stderr = ""; +proc.stderr.on("data", (chunk) => { + stderr += chunk; +}); + +const TIMEOUT_MS = 15000; + +const timeout = setTimeout(() => { + if (stderr.includes("running on stdio")) { + console.log("OK: AgriValue MCP server started"); + console.log(` .mcp.json → node ${server.args?.join(" ") ?? "scripts/mcp-launcher.mjs"}`); + proc.kill(); + process.exit(0); + } + console.error(`FAIL: MCP server did not log startup within ${TIMEOUT_MS / 1000}s`); + console.error(stderr || "(no stderr — try: npm run mcp:cli)"); + proc.kill(); + process.exit(1); +}, TIMEOUT_MS); + +proc.on("error", (err) => { + clearTimeout(timeout); + console.error("FAIL: could not spawn MCP server:", err.message); + process.exit(1); +}); + +proc.on("exit", (code) => { + clearTimeout(timeout); + if (stderr.includes("running on stdio")) { + console.log("OK: AgriValue MCP server started"); + process.exit(0); + } + if (code !== null && code !== 0) { + console.error("FAIL: MCP server exited early with code", code); + console.error(stderr || "(no stderr)"); + process.exit(1); + } +});