MCP server for scanning and querying North Carolina eVP (electronic Vendor Portal) solicitations database, with focus on software development opportunities
Three tools with basic descriptions and varying schema completeness. Tool naming is verb-driven (scan, get_solicitations, get_stats), which is good. However, descriptions are terse (30-90 chars), parameter descriptions exist but lack detail on constraints/formats, and error handling is minimal. The `get_solicitations` tool has a reasonable schema with type info, but `scan` and `get_stats` have empty input schemas. Output schemas are not explicitly documented, responses are JSON strings, but the shape of that JSON is not formally defined. The rubric baseline for A+ tools is descriptions of 50-200 chars and 100% of params with descriptions; this server falls short.
Retrieve state procurement solicitations from the database. Args: limit: Maximum number of records to return (default 10) department: Exact department name to filter by (optional) status: The expected status (e.g., "Open", "Under Evaluation"). Set to None to ignore status. search_term: Text to search in title or description. (optional) Returns: JSON string of matching solicitations.
Get overall statistics about the scraped solicitations database.
Scan the NC eVP website for new software development solicitations and update the database. Run this when the database is missing or to get the latest updates.
scan and get_stats have empty input schemas ({}). Per HARD SCORING RULE, tools with NO input schema must score 0 for schema.
Output schemas not documented. Tools return JSON strings, but the structure (fields, types) of that JSON is not formally specified. LLMs cannot plan downstream tool calls without knowing what fields to expect.
Tool descriptions are terse (30 - 90 chars). Rubric baseline for A+ tools is 50 - 200 chars. 'scan': 116 chars is marginal; 'get_stats': 56 chars lacks detail on what 'statistics' means.
Parameter descriptions in get_solicitations lack specificity. 'status': 'The expected status (e.g., "Open", "Under Evaluation"). Set to None to ignore status.' does not enumerate valid values or explain how None is passed from the LLM context. 'limit': no min/max constraints stated.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | F | 47 | 2026-07-28+ | v2 |
| 2026-03-09 | F | 13 | - | v1 |
No error guidance. When the database is not found, errors say 'Please run the scan tool' but do not use error classification or recovery patterns. LLMs cannot infer whether to retry, ask the user, or move to a different tool.
scan tool is asynchronous (async def) but uses subprocess for the actual work, adding latency and complexity. Description does not mention the tool is a write operation with side effects (database mutation).
get_solicitations accepts a 'status' parameter defaulting to 'Open'. This default constrains results silently, an LLM asking for 'all solicitations' will only get Open ones unless it explicitly passes status=None. Documentation notes this, but the behavior is not intuitive.