Skip to content

Add incumbent-on-post example: agent + MCP, scorer, evals - #12

Merged
vdavez merged 3 commits into
mainfrom
add-incumbent-on-post-example
Jun 19, 2026
Merged

Add incumbent-on-post example: agent + MCP, scorer, evals#12
vdavez merged 3 commits into
mainfrom
add-incumbent-on-post-example

Conversation

@makegov-mark

@makegov-mark makegov-mark Bot commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

What

A new example, examples/incumbent-on-post/: when a new opportunity hits SAM.gov, brief the likely incumbent, the prior award value, and whether the money is still flowing — from one notice.

It's the cookbook's first MCP integration. Every other example hand-wires the tango-python SDK; here the tool catalog comes from the hosted Tango MCP server (https://govcon.dev/mcp) and a PydanticAI agent drives it.

pipeline

Why this shape

The obvious join — match the new opportunity to the prior contract on the solicitation number — doesn't work: a fresh recompete gets a brand-new number; the predecessor award carries the old one. There's no clean key. So the recipe pivots on the contracting office (the thing that persists across a recompete) and ranks candidates by whose award is expiring near the notice — not by who won most recently. Because that's an inference, the output is a ranked shortlist with confidence + evidence, never a single asserted name, with "likely new work" as a first-class answer.

The files

File Role
brief.py PydanticAI agent over the hosted Tango MCP → typed IncumbentBrief (the easy version).
scorer.py Deterministic candidate ranking (expiry-window × dollars × recurrence), bounded server-side with expiring_gte/lte — reproducible, eval-able (the honest version).
evals.py Structural invariants on the scorer; runs without an LLM key.
sample_notice.json A realistic enriched notice to run against.
demo.svg Self-contained pipeline diagram, built from a real run.

Plus: just incumbent / just incumbent-evals, pydantic-ai-slim[anthropic,mcp,openai] added to the examples dependency group, and both README tables updated.

Model: hosted or local

The agent uses the hosted Anthropic model by default, but runs against any OpenAI-compatible server (LM Studio, Ollama, vLLM) by setting OPENAI_BASE_URL + MODEL — at which point ANTHROPIC_API_KEY isn't needed. The MCP server (hosted vs. local stdio) is an independent axis. Both are documented in the example README.

Testing

  • just incumbent-evals — all scorer invariants hold against the live API (top court-reporting incumbent at VA NCO 5 resolves to Vet Reporting LLC; far-future window correctly returns "new work").
  • just incumbent — agent connects to the hosted MCP and returns a structured 3-candidate brief, independently agreeing with the scorer's top pick, and catching a real office-code disambiguation (36C250 vs 36C245).
  • demo.svg validates as XML.

Per repo convention, this example is not run in CI (it calls a paid LLM and a live API); evals.py is deterministic but still hits the live API.

Risks / notes

  • demo.svg hardcodes the sample brief's specifics (vendor names, 2029 recompete date, −3% funding figure). If sample_notice.json changes, the diagram drifts from a fresh run — kept real for impact; easy to genericize if preferred.
  • The funding signal is wired through the schema/prompt but is the lightest part of the agent's job; deepening it with get_budget_account + quarterly cash flow is a documented next step.

🤖 Generated with Claude Code

vdavez and others added 3 commits June 18, 2026 19:23
When a new opportunity posts, brief the likely incumbent, prior award, and
funding from one notice. This is the cookbook's first MCP integration — a
PydanticAI agent drives the hosted Tango MCP rather than hand-wiring the SDK.

The recipe is built around an honest arc: a fresh recompete gets a new
solicitation number, so it never joins to the prior award on the number. The
pivot is the contracting office, and the incumbent is whoever's award is
expiring near the notice — an inference, so the output is a ranked shortlist
with confidence and evidence, never a single asserted name, with "likely new
work" as a first-class answer.

- brief.py: PydanticAI agent over the hosted Tango MCP, returning a typed
  IncumbentBrief (the easy version).
- scorer.py: deterministic candidate ranking (expiry-window x dollars x
  recurrence), bounded server-side — reproducible and eval-able (the honest
  version).
- evals.py: structural invariants on the scorer; runs without an LLM key.
- demo.svg: self-contained pipeline diagram built from a real run.
- just incumbent / just incumbent-evals; pydantic-ai-slim added to the
  examples group; README tables updated.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Let brief.py run against any OpenAI-compatible server (LM Studio, Ollama, vLLM)
in addition to the hosted Anthropic default. Set OPENAI_BASE_URL + MODEL to point
at a local server; ANTHROPIC_API_KEY is then no longer required. Adds the openai
extra to pydantic-ai-slim.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Note the two independent "local" axes (MCP server vs. model) and show how to
point the agent at an OpenAI-compatible server via OPENAI_BASE_URL + MODEL.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@vdavez
vdavez merged commit 55db727 into main Jun 19, 2026
4 checks passed
@vdavez
vdavez deleted the add-incumbent-on-post-example branch June 19, 2026 01:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant