{"id":31327997,"url":"https://github.com/prynai/prynai-mcp","last_synced_at":"2026-04-07T07:47:22.787Z","repository":{"id":316527825,"uuid":"1063747571","full_name":"PrynAI/PrynAI-MCP","owner":"PrynAI","description":"Enterprise-grade MCP server implementation with HTTP streamable transport, OAuth 2.0 authentication, and end-to-end HTTPS encryption. Designed for reproducibility, observability, and secure deployment on Azure Container Apps","archived":false,"fork":false,"pushed_at":"2025-09-25T04:40:18.000Z","size":41,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-09-25T06:21:44.425Z","etag":null,"topics":["agents","azurecontainerapps","docker","mcp","oauth2","python","redis","streamable-http-transport"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/PrynAI.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-25T04:16:49.000Z","updated_at":"2025-09-25T04:40:22.000Z","dependencies_parsed_at":"2025-09-25T06:32:13.424Z","dependency_job_id":null,"html_url":"https://github.com/PrynAI/PrynAI-MCP","commit_stats":null,"previous_names":["prynai/prynai-mcp"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/PrynAI/PrynAI-MCP","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PrynAI%2FPrynAI-MCP","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PrynAI%2FPrynAI-MCP/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PrynAI%2FPrynAI-MCP/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PrynAI%2FPrynAI-MCP/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/PrynAI","download_url":"https://codeload.github.com/PrynAI/PrynAI-MCP/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/PrynAI%2FPrynAI-MCP/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":276997720,"owners_count":25742502,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-25T02:00:09.612Z","response_time":80,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agents","azurecontainerapps","docker","mcp","oauth2","python","redis","streamable-http-transport"],"created_at":"2025-09-25T23:40:55.021Z","updated_at":"2025-12-30T21:21:05.299Z","avatar_url":"https://github.com/PrynAI.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# PrynAI MCP — Self-hosted MCP Server\n\nProduction-ready **Model Context Protocol (MCP)** server plus client examples that show how to:\n- Run locally and in Docker\n- Deploy to **Azure Container Apps (ACA)** behind **Entra ID (OAuth2 client credentials)**\n- Use **Azure Cache for Redis** for state\n- Call MCP tools/resources/prompts from **LangGraph** and **LangChain** agents\n- Roll out new server revisions safely (blue/green via ACA revisions)\n\n\u003e 📚 Step-by-step guides live in [`/docs`](./docs): [Phase 1](./docs/phase1.md) · [Phase 2](./docs/phase2.md) · [Phase 3](./docs/phase3.md) · [Phase 4](./docs/phase4.md) · [Phase 5](./docs/phase5.md)\n\n---\n\n## Repo layout\n\n.\n├─ server.py # MCP server (tools/resources/prompts)\n├─ src/prynai/mcp_core.py # Client helpers: auth, MCP sessions, LangChain tools\n├─ examples/ # Smoke tests for each phase\n│ ├─ smoke_oauth_ccACADeployment.py\n│ ├─ phase5_langgraph_smoke.py\n│ ├─ phase5_langchain_create_agent_alltools_smoke.py\n│ ├─ use_core_list_tools.py\n│ └─ use_core_langchain_agent.py\n├─ infra/\n│ ├─ docker/Dockerfile\n│ ├─ docker-compose.yml\n│ └─ azure/\n│ ├─ deploy_aca.ps1 # First-time deploy (env + app)\n│ └─ deploy_update.ps1 # Remote build in ACR + new ACA revision + traffic\n├─ docs/ # Phase guides\n└─ .env.example # Sample environment\n\n\n---\n\n## Features\n\n- ✅ MCP Server (HTTP streamable) with example tools: `add`, `echo`, `long_task`, `bump_counter`, `summarize_via_client_llm`\n- ✅ MCP resources (e.g., `prynai://status`, `prynai://counter`)\n- ✅ MCP prompts (e.g., `quick_summary`)\n- ✅ OAuth2 (Entra ID client credentials) on `/mcp`\n- ✅ Redis-backed state (counter)\n- ✅ ACA deployment with **remote image builds** in ACR and **multi-revision** rollouts\n- ✅ LangGraph + LangChain agents that auto-discover MCP tools\n\n---\n\n## Quick start\n\n### 1) Clone \u0026 create env\n```bash\ngit clone https://github.com/PrynAI/PrynAI-MCP.git\ncd PrynAI-MCP\ncp .env.example .env\n# Fill in: PRYNAI_MCP_URL, ENTRA_* , SERVER_APP_ID_URI, OPENAI_API_KEY/OPENAI_MODEL, REDIS_*\n```\n\n### 2) Run locally (Python)\n\n```\nuv sync\nuv run python examples/use_core_list_tools.py\nuv run python examples/use_core_langchain_agent.py\n```\n\n## Deploy to Azure Container Apps\n\n### First-time (creates env, app, wiring): see docs/phase4.md\n\n### Updates (safe remote build + new revision):\n\n# From repo root\n.\\infra\\azure\\deploy_update.ps1\n# Script prints preview FQDN; smoke test it, then promote 100% traffic (also printed).\n\n## Versioning \u0026 releases\n\n- Tags: MAJOR.MINOR.PATCH-qualifier (e.g., 0.5.0-phase5)\n\n- Create annotated tags and optional GitHub Releases.\n\n- Deployment scripts accept -Tag to pin the image.\n\n## Contributing\n\n- Fork \u0026 create a feature branch.\n\n- Add/modify tools in server.py (sync or async are supported).\n\n- Add tests/smoke in examples/.\n\n- Run ruff/black (if configured) and uv run smoke tests.\n\n-Open a PR with a clear description.\n\n⚠️ Never commit secrets. .env is local only.\n\n## Support\n\n- Issues: GitHub Issues\n\n- Security: security@ (responsible disclosure)\n\n\n---\n\n### `docs/phase1.md`\n\n```markdown\n# Phase 1 — Local MCP server \u0026 first tool\n\n## Goal\nRun the MCP server locally, expose a health check, and implement basic tools/resources/prompts.\n\n## What you get\n- `server.py` with tools: `add`, `echo`\n- Resource: `prynai://status`\n- Prompt: `quick_summary` (simple template)\n- Local smoke tests under `examples/`\n\n## Prereqs\n- Python 3.11+ and `uv`\n- (Optional) Docker if you prefer containers\n\n## Setup\n```bash\ncp .env.example .env\n# For Phase 1 local runs you can temporarily leave OAuth off or point to dev values.\nuv sync\n```\n\n### Run\n\n```\nuv run python examples/smoke_http_phase1.py\n# Lists tools via HTTP stream to /mcp (no OAuth in this phase)\n\nMCP tools discovered: ['add', 'echo', ...]\n```\n\n## Move to Phase 2 to add Redis and stateful behavior.\n\n\n---\n\n### `docs/phase2.md`\n\n```markdown\n# Phase 2 — Redis state (counter)\n\n## Goal\nAdd Redis to persist state and expose a counter as an MCP resource/tool.\n\n## What you get\n- Redis connection (via `REDIS_URL` or host/port/password)\n- `bump_counter` tool\n- `prynai://counter` resource\n\n## Prereqs\n- A Redis instance (local or cloud)\n- Update `.env` with Redis settings\n\n## Run locally\nbash\n# Option A: docker compose (includes Redis)\ndocker compose up --build\n\n# Option B: your own Redis, run server with uv\nuv run python examples/use_core_list_tools.py\nuv run python examples/use_core_langchain_agent.py\n```\n\n### Smoke\n\n\n# List tools and call counter\nuv run python examples/use_core_list_tools.py\n# Expect 'bump_counter' and resource 'prynai://counter'\n\n## Troubleshooting\n\n- If counter doesn’t change, verify Redis connectivity and credentials.\n\n- Make sure the server process can reach Redis from its network.\n\n\n---\n\n### `docs/phase3.md`\n\n```markdown\n# Phase 3 — OAuth (Entra ID client credentials)\n\n## Goal\nProtect `/mcp` with Entra ID (Azure AD) OAuth2 (client credentials flow).\n\n## What you get\n- Server validates `Authorization: Bearer \u003ctoken\u003e`\n- Example client code to fetch tokens via `msal`\n\n## Configure Entra\n- **App registrations**: one for the server (expose API), one for the client\n- Record:\n  - `ENTRA_TENANT_ID`\n  - `ENTRA_CLIENT_ID`, `ENTRA_CLIENT_SECRET` (client app)\n  - `SERVER_APP_ID_URI` (e.g., `api://\u003cserver-app-id\u003e`)\n\nUpdate `.env`:\n```\n\n### ENTRA_TENANT_ID=...\n### ENTRA_CLIENT_ID=...\n### ENTRA_CLIENT_SECRET=...\n### SERVER_APP_ID_URI=api://...\n\n\n## Smoke\n```bash\nuv run python examples/smoke_oauth_ccACADeployment.py\n# Shows 401 if missing token, 200 with token; lists tools \u0026 reads resources.\n```\n\n## Troubleshooting\n\n- 401/missing_or_malformed: check Authorization header and scopes (\u003cSERVER_APP_ID_URI\u003e/.default).\n\n- SSL issues: ensure you haven’t set custom CA/proxy envs locally unless intended.\n\n\n---\n\n### `docs/phase4.md`\n\n```markdown\n# Phase 4 — Azure Container Apps deployment\n\n## Goal\nDeploy the MCP server to **Azure Container Apps (ACA)**, use **Azure Container Registry (ACR)** for images, and wire **Redis** \u0026 OAuth secrets.\n\n## Azure resources (example names)\n- RG: `prynai-mcp-rg`\n- ACA Env: `prynai-aca-env`\n- Container App: `prynai-mcp` → `https://\u003cfqdn\u003e/mcp`\n- ACR: `prynaiacr44058.azurecr.io`\n- Azure Cache for Redis: e.g., `prynai-redis.redis.cache.windows.net`\n\n## First-time deploy\nUse `infra/azure/deploy_aca.ps1` (provisions env/app + initial image). Fill environment in the script or pass parameters as needed.\n\n## Updating (safe rollout)\nUse **remote build** + **revision traffic** via:\n```powershell\n.\\infra\\azure\\deploy_update.ps1 -Tag 0.5.0-phase5\n# Script prints a new revision FQDN for smoke tests and the promote command.\n\n### What the update script does:\n\n- Builds a new image in ACR (no local Docker needed).\n\n- Creates a new ACA revision with that image.\n\n- Keeps multiple revisions enabled for safe testing.\n\n- You manually promote traffic to 100% when satisfied.\n\n\n## Promote to 100%\n\n### The script prints the exact az containerapp ingress traffic set ... command with the new revision name.\n\n## Troubleshooting\n\n- If a revision gets a new sub-FQDN, that’s expected in “multiple revisions” mode. Your stable app URL stays the same once you promote.\n\n\n---\n\n### `docs/phase5.md`\n\n```markdown\n# Phase 5 — Agents (LangGraph \u0026 LangChain) + LangSmith\n\n## Goal\nDemonstrate agents that **discover and call MCP tools** and prompts. Show both **LangGraph** and **LangChain** flows. Optional **LangSmith** tracing.\n\n## What you get\n- `examples/phase5_langgraph_smoke.py`: 5-step graph\n  1) Acquire Entra token\n  2) List tools\n  3) Call `add`\n  4) Read `prynai://status` \u0026 `prynai://counter`\n  5) Render `quick_summary` and ask OpenAI to summarize\n- `examples/phase5_langchain_create_agent_alltools_smoke.py`: build **all** MCP tools into LangChain tools and let the agent pick\n- `examples/use_core_langchain_agent.py`: minimal `create_agent` usage\n- `src/prynai/mcp_core.py`: **reusable** building block to:\n  - fetch token\n  - create MCP sessions\n  - convert MCP tool catalog → LangChain tools (with Pydantic arg models)\n  - (Optionally) return a single “add-only” tool if you want a scoped agent\n\n## Env\n```\n\nPRYNAI_MCP_URL=https://\u003cyour-aca-fqdn\u003e/mcp\nENTRA_TENANT_ID=...\nENTRA_CLIENT_ID=...\nENTRA_CLIENT_SECRET=...\nSERVER_APP_ID_URI=api://...\nOPENAI_API_KEY=...\nOPENAI_MODEL=gpt-4o-mini\n\n## Optional LangSmith\n\nLANGCHAIN_TRACING_V2=true\nLANGSMITH_API_KEY=...\nLANGSMITH_PROJECT=PrynAI-MCP\n\n\n## Run\n```bash\nuv run python examples/phase5_langgraph_smoke.py\nuv run python examples/phase5_langchain_create_agent_alltools_smoke.py\nuv run python examples/use_core_langchain_agent.py\n```\n\n## Adding new tools\n\n- Implement sync or async functions in server.py. Both work.\n\n- Register them like existing tools; include helpful docstrings (agents read these).\n\n- If args are structured, ensure they’re validated server-side (Pydantic or your schema).\n\n- Re-deploy with infra/azure/deploy_update.ps1 -Tag \u003cnew-tag\u003e and smoke test the new revision before promoting.\n\n\n\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprynai%2Fprynai-mcp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fprynai%2Fprynai-mcp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fprynai%2Fprynai-mcp/lists"}