Skip to main content
Glama

Look up a North Carolina (NC) court case (by number, citation, or hash)

lookup_court_case
Read-only

Look up a North Carolina (NC) court case or traffic citation.

Provide a case number (e.g. "26CV001234-012"), a citation number (e.g. "92403H2"), OR a portalSessionRef from a search_cases_by_party row. caseNumber is the STABLE, canonical identifier — prefer it for anything that isn't an immediate follow-up. portalSessionRef is a fast path that resolves an already-searched case without re-running the portal search. Its lifetime is UNSPECIFIED and not guaranteed — the value rotates on every search and should be treated as short-lived (it survives at least minutes; the upper bound is unmeasured); never persist or reuse it. (caseHash is accepted as a deprecated alias for portalSessionRef.) Returns case status, upcoming and recently-elapsed hearing dates/times/ locations, charges (including speed fields for traffic cases), and — for traffic charges — whether each charge is waivable or requires a court appearance under the NC AOC schedules, plus how to request a reduction or dismissal (online via NC Guide & File when the county participates, else in person via the District Attorney) in citationOptions.howToRequest. Those are OPTIONS WITH CONSEQUENCES, NOT A RECOMMENDATION: waiving is a guilty plea to the charge as written (an admission of responsibility on an infraction), while a reduction changes the charge before any plea, and both have to be completed BEFORE THE CASE IS CALLED — not merely on or before the court date. Present them as choices, not advice; citationOptions.notice carries this caveat verbatim.

citationOptions.state IS THE RESOLUTION PATH AND OUTRANKS THE PER-CHARGE CLASSES. Two of its values turn on the clock, and both forbid "no appearance needed" no matter how many charges read waivable: "lastDay" (the hearing is TODAY — settleable with the clerk only before the case is called, no time to file online) and "noCourtDate" (no upcoming hearing, or today's has already been called — do not assert a failure to appear, since the person may have attended that morning). Relay howToRequest verbatim and it will be right for every state.

Read-only: no email is sent and nothing is saved. North Carolina only. Informational, not legal advice.

EVERY LOOKUP ENDS WITH TWO THINGS, PER CASE. Both are spelled out in present_to_user, the FIRST key of this result, already filled in for this particular case — read it and do what it says. (1) caseSummaryUrl — hand it to the user and call it the durable, shareable link to the full case record. It does not expire, it is publicly viewable, and the same case returns the same link every time, so it is the canonical way to cite or share the case. THE KEY IS ALWAYS PRESENT, so "when it appears" is not the test — the VALUE is: non-null means give it; null means minting failed on this lookup, so say nothing about a link rather than substituting trackThisCase.url, a portal URL, or a guess. (2) alerts — when alerts.available is true, ask whether they'd like email alerts when the case changes: a new court date, case information, case events, service events, or financial updates. ASK and wait for a yes. Never call subscribe_to_case_updates on your own initiative and never invent an email address. When available is false the case is closed, disposed, or not found — nothing would ever be sent — and you must not raise it. IN A MULTI-CASE TURN DO BOTH FOR EACH CASE, beside that case's own details. Two cases means two links and two offers; one combined link, or a single offer at the end of the answer, is wrong. (A search row's portal_url is ephemeral by contrast — don't present that as durable or persist it.) upcomingHearings lists only FUTURE hearings; pastHearings lists recently- elapsed ones (most recent first). The top-level status of "no_upcoming_hearings" means exactly that — NOT that the case has no hearing history. Before telling the user they have no court date, check pastHearings: an empty upcomingHearings with a non-empty pastHearings means a hearing has ALREADY occurred (they may have missed it) — a different answer than "nothing scheduled." Never infer "you didn't miss court" from an empty upcomingHearings/status alone. service answers "was the defendant actually reached?" on civil / SP / estate cases — the civil-side counterpart to bailRisk, and null on criminal/traffic, where service of process does not apply (null there = NOT APPLICABLE, not "not served"). Read status FIRST; three of its values mean the absence of a return is EXPECTED and must never be reported as "not served":

  • served / unserved / mixed — a return of service is docketed. mixed means both outcomes appear (several defendants, or the alias-and-pluries retry cycle).

  • proven_other — a certificate / affidavit / acceptance of service instead of a formal return. Still proof.

  • appeared_service_moot — the defendant answered or appeared, which waives a service defect. Service became unnecessary.

  • not_required — an appeal or petition; no summons is issued at all.

  • pending — a summons went out recently and nothing is back YET. Say "service is still outstanding", NOT "they weren't served".

  • unknown — a summons issued, nothing returned, and the case isn't new. returns[] is the full history (the retry cycle is often the story) and latestReturn the most recent attempt. returns[].party is NULL about a third of the time — the docket records the outcome without naming who it applied to — so never read a null party as "nobody". For the same reason there is deliberately NO per-defendant served flag: one case in the sample had a single docketed return against 41 defendants, and a per-party boolean would be confidently wrong. legacyScan:true means the paper file was scanned as ONE bundle rather than itemised, so proof of service may sit inside that PDF where no docket-text rule can see it — a missing return is weak evidence on those cases. causesOfAction is the civil counterpart to charges — the claims pleaded (cause, filedOn, remedy), e.g. "CV - Unfair Trade Practice". On a civil / SP / estate case this is usually the ONLY statement of what the matter is about, so lead with it there. An empty list means the docket does not ITEMISE causes, NOT that no claims exist — say the docket doesn't break them out rather than implying the case is about nothing. Repeated boilerplate entries are collapsed; distinct dates are kept, since a cause added later is an amendment. Each charge also carries offenseDate (when the offense occurred — different from the case's filedOn, and usually what someone means by "when was this?") and agency (the citing law-enforcement agency). If a tool returns an error with retryable / upstream_status, that is a transport or portal failure — NOT a statement about the case. Never turn it into "no results" or "case not found"; say the lookup itself failed, and retry only when retryable is true. caseCategory normalizes the case class (criminal | civil | infraction | special_proceeding | estate | juvenile | other). Use it to read null fields correctly: on a NON-criminal category, bailRisk/citationOptions = null means NOT APPLICABLE, not "none found." parties is the register-of-actions roster (name + roles[] + attorneys[]{name, appointment} + selfRepresented + counselWaived) — appointment is how counsel came to the case ("Retained" = the party hired them, vs "Court Appointed" / "Public Defender"; null when unstated, and the list is learned from the register rather than a closed set). It is what makes a counselWaived:true party who nonetheless HAS counsel intelligible — appointed, then a waiver, then retained. The authoritative source for identifying who is on a case and their role, especially on civil/SP cases where the caption/DOB are absent; prefer it over a party-search row's caption for entity resolution. selfRepresented:true = no counsel of record (self-listed as own attorney OR a filtered counsel-absence sentinel, with no other attorney); it does NOT distinguish an active pro-se appearance from a defaulted / served-by-publication defendant. counselWaived is a SEPARATE, independent flag — NOT a narrowing of selfRepresented — and it is NOT a claim the party is unrepresented: it can be true while attorneys[] is non-empty (seen on 22CR702455-520, counselWaived:true with a Court Appointed AND a Retained attorney, the docket running appointed counsel -> Waiver of Counsel -> retained counsel). Always read it WITH attorneys[], never instead of it. counselWaived is set by either Odyssey placeholder "attorney" name, filtered out of attorneys[] rather than shown as a lawyer: "WAIVED, WAIVED" (counsel affirmatively waived on the record — the docket does not say whether the waiver covered all assistance of counsel or only court-appointed counsel) or "PRO SE" (the party asserted as their own representation). Either means the party declined counsel rather than merely lacking it, but the flag does NOT say which placeholder produced it, so it is not proof the party is litigating pro se. counselWaived:false means NOT OBSERVED, not "did not waive". A true value is predominantly a criminal-side artifact and is rare on civil rosters — treat it as unexpected but NOT impossible on a non-criminal caseCategory; don't read one there as an error. A false unrepresented party is still any of defaulted / never-served / unappeared-entity / pro-se-without-a-docketed-marker — or simply TOO EARLY: on a recently-filed case that has not had a hearing yet, counsel is frequently not entered on the roster. parties reflects what is DOCKETED, not who is retained; check filedOn and an empty pastHearings before reading an empty attorneys[] as unrepresented — on a pending case that has not been to court, "not shown yet" is usually the better answer than "no lawyer." attorneys[] non-empty ⇒ represented ⇒ selfRepresented false. documents lists scanned filings, newest first — {date, name, url}, where name is the register entry that produced it ("Bond Forfeiture Notice", "Release Order Issued", "Waiver of Counsel"). Most criminal cases have at least one; an empty list means nothing is scanned in, not that nothing was filed. Offer the links when they're relevant to what was asked. Retrieval is UNRELIABLE — the portal intermittently returns errors or an empty body while it prepares a document — so present a link as something that may need a retry, never as "here is the document", and never state or guess at its contents: this server does not read them. dispositions gives the per-charge OUTCOME behind a "Disposed" status — one row per charge with plea, disposition, sentence, dispositionDate, judge, and any judgment documentUrls. This is how you answer "what happened to the case / to a charge": a "Disposed" caseStatus alone does not say whether a charge was dismissed, pled down, or convicted — read dispositions for that (e.g. a speeding charge reduced to improper equipment shows plea "Responsible to Lesser"; a "VD-District Dismissals ... Per Plea Agreement" is a dismissal). Empty on pending/undisposed cases. trackThisCase is an upstream ELIGIBILITY FLAG (non-null only on an open case), not something to act on: this server already consumes it — it is what gates alerts.available — so don't reason from it, and never show trackThisCase.url to the user. That is a generic signup page with no case identity. The case-specific paths are caseSummaryUrl and, once the user has said yes, subscribe_to_case_updates. For criminal cases with a bond or bail activity, bailRisk is non-null: failure-to-appear history (ftaCount, date-deduped; ftaEvents[] gives the raw counted entries {date, description} for auditing — voided "in Error/Stricken" FTAs are already excluded), FTA-triggered ordersForArrest, bond amount/type, and the NCGS §15A-544.5(f) prior-FTA bar. That bar turns on FTAs that preceded the bond's EXECUTION, not the case total: bondExecutedOn is the "Bond Posted" date for the operative bond and priorFtasAtExecution counts FTAs strictly before it (null when no posting is docketed).

  • setAsideBarInapplicable:true (0-1 prior FTAs) is RELIABLE — (f) cannot bar a set-aside. State it plainly; it's the answer that tells someone a motion is worth filing.

  • setAsideBarPossible:true (2+ prior) is NOT a finding that the bar applies. It means only that the TIMING fits. Under (f), actual notice exists ONLY where a judicial official noted the prior failures on the defendant's release order. Check releaseOrderFBox below before saying anything further, and never say "the forfeiture cannot be set aside" on the strength of this flag alone.

  • Both false = execution date unknown; neither ruled out nor suggested. releaseOrderUrl is the portal PDF of the release order governing that bond — the document the (f) question actually turns on, since the judicial official's "second or subsequent failure to appear" notation appears there (AOC-CR-200) and in NO structured field. ALWAYS present this link when setAsideBarPossible is true, even when the read below already answered the question: the order is the authority. releaseOrderFBox IS THAT READ, present only on barred cases where the order could be fetched and parsed. Report it, and report it precisely — this is the field that decides whether someone spends their one motion:

  • "unchecked" — on its face (f) does NOT bar a set-aside; the prior FTAs do not block relief and it is worth pursuing. Say so, and add that they should confirm it on the order before relying on it.

  • "checked" — (f) MAY bar it. Do NOT say "cannot be set aside". Tell them to confirm on the order BEFORE filing, because a motion that fails uses up the single opportunity for relief.

  • "ambiguous" — the order was opened and the box could NOT be read. Say exactly that, and hand over the link. The notation is a flattened checkbox with no glyph in the text layer, so the printed label appears whether or not it is marked. NEVER round this to "unchecked": a misread tells a bondsman to abandon a recoverable bond.

  • absent / null — no read was attempted (not a barred case, no order docketed, or the fetch failed). This is ALSO not "unchecked". Fall back to the link. For the forward-looking question ("could a bond I write NOW be barred?") use ftaCount: 2+ FTAs on the case means the next release order should carry the judicial notation — tell the user to read it before signing. Then forfeiture with its status (the latest DOCKETED forfeiture event — may lag the clock) and the 150-day set-aside clock (noticedOn, deadline, daysRemaining, windowOpen). noticeAnchor says where noticedOn came from: "notice_event" = an explicit forfeiture NOTICE line (the date the statute runs the 150 days from); "earliest_forfeiture_event" = no notice was docketed, so the earliest forfeiture entry stands in — the deadline is then a CONSERVATIVE proxy (earlier than the true notice), and daysFtaToNotice measures FTA-to-forfeiture rather than FTA-to-notice. Don't present a proxy-anchored deadline as the exact statutory date — treat windowOpen/daysRemaining as authoritative for whether the set-aside window is open; once windowOpen is false the window has closed even if status still reads in_effect. deadlineNextBusinessDay is the first day the clerk's office is open on or after deadline (equal to it when that is already a business day; later when it falls on a weekend or NC court holiday). ADVISORY ONLY — it never moves daysRemaining / windowOpen, which stay on the strict notice+150 date, because the safe error is telling someone they have LESS time, never more. null = UNDETERMINED (deadline year outside the published NC holiday calendar), NOT "no adjustment needed"; never present a null as though the deadline is a normal business day. triggeringFta (latest counted FTA on or before noticedOn) and daysFtaToNotice (the gap in days) report HOW LONG after the failure the forfeiture notice was docketed. Report the number; do NOT call a long gap a defect or a filing error — there is deliberately no threshold flag, and whether a gap affects the notice's validity is for the reader's attorney. Plus the bonding agent (Fiduciary) + surety (insurer). All from public NC eCourts records. (citationOptions is null on disposed/closed cases — the reduction path isn't live.) Informational underwriting signal, not legal advice; don't state legal conclusions.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
caseHashNo
citationNo
caseNumberNo
portalSessionRefNo

Output Schema

TableJSON Schema
NameRequiredDescriptionDefault

No arguments

Schema Changelog

Changes observed during successful MCP inspections.

  1. First observed

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only say readOnlyHint/openWorldHint, but the description adds read-only semantics (no email sent, nothing saved, NC only, informational not legal advice), error-contract handling (`retryable`/`upstream_status` is a transport failure, not 'case not found'), liveness warnings (`portalSessionRef` lifetime unspecified and rotating; document retrieval unreliable), and null-reading rules across many fields. This is far beyond what the annotations carry.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The core lookup and identifier guidance is correctly front-loaded, but the description then runs to roughly 1500 words with deep dives into dozens of output fields, repeating rules in multiple places. Most statements are individually useful, yet the sheer volume and the number of caveats make it hard to scan; it is over-specified relative to what an agent needs to select and invoke the tool.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need not be explained, yet the description still supplies the interpretive rules that the schema cannot (null = not applicable vs not found, deprecated alias handling, empty-list meanings). Nothing an agent needs to call this correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description carries the full burden, and it does: it defines each of the four parameters, gives format examples for `caseNumber` and `citation`, explains that `portalSessionRef` is short-lived and must not be persisted, and marks `caseHash` as a deprecated alias. None of the parameters is left ambiguous.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence states a specific verb (look up) and resource (NC court case or traffic citation), and the next lines spell out the three accepted identifiers with examples. It also distinguishes itself from siblings by naming `search_cases_by_party` as the source of `portalSessionRef` and framing this tool as the follow-up to that search.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly ranks the identifiers: `caseNumber` is the STABLE canonical choice, `portalSessionRef` is an immediate-follow-up fast path, and `caseHash` is a deprecated alias. It also gives when-to-use context for the returned alert flow (ask, wait for yes, never call `subscribe_to_case_updates` on your own initiative), which is unusual and genuinely directive.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.

Resources