Skip to main content
Glama
adamselzer

rules-as-code-mcp

by adamselzer

rules-as-code-mcp

Deterministic SNAP eligibility logic, exposed as auditable Model Context Protocol tools. An AI agent can read, reason, and orchestrate, but the eligibility determination itself is made by versioned, tested, cited code that a caseworker, an auditor, or a court can inspect.

This is the keystone of a four-project portfolio on AI in the public benefits safety net. It is the layer the other three projects hand the actual legal decision to.

In government, "the model said so" is not a basis for denying someone food or medical coverage. The boundary between what a model decides and what code decides is the whole reason agentic AI is deployable in the public sector. This project puts that boundary on the table and exposes it over MCP.

What it does

A household's facts go in. A determination comes out with its reasoning attached. Every determination carries:

  • the decision (eligible / ineligible),

  • the rule trace: each rule that fired, what it saw, and what it concluded,

  • a policy citation behind every rule (7 CFR, USDA FNS, or the Michigan Bridges Eligibility Manual),

  • the ruleset version and the policy effective dates it was computed under,

  • a reproducible determination id (a hash of the inputs, not a random id, so re-running the same case reproduces the same id).

It implements the federal SNAP financial eligibility test for the 48 contiguous states and DC (FY2026 figures), with Michigan's broad-based categorical eligibility applied as a state option.

Related MCP server: calcfi-mcp

Quickstart

python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"

pytest                              # 83 unit tests over the rules core and server
python eval/run_eval.py             # determination correctness (writes eval/report.md)
python eval/run_server_eval.py      # server robustness (writes eval/server_report.md)
python clients/demo_client.py       # drive the server over stdio (writes a transcript)

To wire the server into Claude Desktop or Claude Code, see clients/demo.md. A captured end-to-end transcript is in clients/demo_transcript.md.

The tools

Few and sharp. Three require the caseworker scope; two are anonymous-safe.

Tool

Scope

Returns

screen_programs(household)

screening

Coarse "likely eligible" signal across SNAP and a simplified Medicaid income screen. Not a determination; stores nothing.

check_program_eligibility(program, household)

caseworker

A full SNAP determination: decision + rule trace + citations + version.

list_required_verifications(program, household)

caseworker

The documents a caseworker must verify, derived from the facts the household presents.

explain_determination(determination_id)

caseworker

A plain, step-by-step trace of a prior determination by id.

lookup_policy(question)

screening

Cited policy answer. Currently an honest stub with a seam to the policy-manual-rag index.

Architecture

rules-as-code-mcp/
├── rules/                     # the deterministic core (no MCP, no network)
│   ├── constants.py           # FY2026 figures, derived from the poverty guidelines
│   ├── citations.py           # rule_id -> policy citation (enforced by tests)
│   ├── version.py             # ruleset version + effective dates
│   ├── models.py              # pydantic domain models (also the validation layer)
│   ├── snap.py                # the determination engine + net-income calculation
│   ├── programs.py            # cross-program screening + verification requirements
│   └── tests/                 # 63 unit tests over the logic
├── server/                    # the MCP boundary
│   ├── main.py                # FastMCP tool registration + error translation
│   ├── tools.py               # pure, scope-aware tool logic
│   ├── auth.py                # screening vs caseworker scope resolution
│   ├── errors.py              # structured, recoverable tool errors
│   ├── store.py               # determination cache for explain_determination
│   └── tests/                 # 20 unit tests over scope + errors
├── clients/                   # real MCP client demo + captured transcript
└── eval/                      # labeled cases + the two eval harnesses

The dependency arrow points one way: server/ imports rules/, never the reverse. The core has no idea it is being served over MCP, which is what keeps it testable in isolation and reusable by the other portfolio projects (the benefits-intake-agent imports this core directly or calls it over MCP).

How the rule logic works

For a household with no elderly or disabled member, eligibility is two income tests with deductions in between:

  1. Asset test. Waived under Michigan's broad-based categorical eligibility.

  2. Gross income test. Gross monthly income at or below 130% of the federal poverty guideline (200% under BBCE). Households with an elderly (60+) or disabled member are exempt from this test.

  3. Net income test. After the statutory deductions (20% of earned income, the standard deduction, dependent care, child support paid, medical expenses over $35 for elderly/disabled members, and the excess shelter deduction), net income must be at or below 100% of poverty.

The excess shelter deduction is capped at $744/month, except for households with an elderly or disabled member, where it is uncapped. All FY2026 dollar figures live in one file, rules/constants.py, each tied to a citation. The income limits are the published USDA standards, independently reproduced in the tests by deriving them from the 2025 HHS poverty guidelines.

When the FY2027 COLA is published, constants.py and version.py change. The logic in snap.py does not. That separation is the point of rules-as-code.

The scope boundary

Two scopes, resolved from the request context and never from a model-supplied argument, so a model cannot escalate its own privileges:

  • screening (anonymous): coarse signals, no PII collected or stored.

  • caseworker (authenticated): full determinations, verifications, and stored explanations.

Over stdio the role comes from the RULES_MCP_ROLE environment variable; over streamable-http it comes from the OAuth bearer token. The domain models carry no names, SSNs, or addresses (only ages and flags), which is what lets anonymous screening exist at all.

Evaluation

Evaluation is the deliverable here. Two harnesses, both runnable as CI gates with --check.

Determination correctness (eval/run_eval.py, 18 hand-derived labeled cases spanning eligible / ineligible / near-threshold / elderly / deduction-edge / asset-waived):

Metric

Result

Decision accuracy

100% (18/18)

Rule-trace correctness (right rules fired)

100% (18/18)

Citation correctness (right citation present)

100% (18/18)

Net-income spot checks

100%

Input-robustness (malformed input rejected)

100% (7/7)

Server robustness (eval/run_server_eval.py): 9/9 failure cases (privilege escalation, unsupported program, unknown id, malformed and out-of-range input) return a clean, correctly-typed, recoverable structured error. None crash; none leak an unauthorized result. The full failure-case table with each structured response is in eval/server_report.md.

The labeled cases were derived by hand from 7 CFR 273.9 and the FY2026 standards, independently of the implementation, so the eval is a real check rather than a restatement of the code.

Synthetic data only, never real PII

Every household this project touches is synthetic and illustrative. Handling applicant data correctly is a hard requirement (you cannot touch real benefits data) and a core public-sector competency, so the design keeps PII out of the domain model entirely and gates all case detail behind the caseworker scope.

How it composes with the rest of the portfolio

  • benefits-intake-agent (the agent) calls check_program_eligibility here rather than reasoning about eligibility itself. The model extracts messy facts; this code makes the call.

  • policy-manual-rag (the RAG index) is what lookup_policy will delegate to, so one server offers both deterministic determination and cited policy lookup.

Each repo also runs standalone.

What I would do differently at production scale

  • Real rule sourcing. The FY2026 figures are hand-entered from USDA and CBPP and verified against the poverty guidelines. At scale these would be ingested from the authoritative releases with a review step, and older rulesets would be retained so any past determination stays reproducible.

  • More than the financial test. SNAP has work requirements, categorical and immigration rules, and state variation this does not model. The architecture (one program, fully cited, versioned) is built to extend to those rather than to hide them.

  • Production auth. The scope model is real, but the HTTP token table is a demonstration stand-in for an identity provider, and over stdio the role is an environment variable. A deployment would issue and validate scoped tokens through the agency's IdP.

  • Persistence and audit. The determination store is process-local. Production needs durable storage with retention and an audit log of who asked for what.

Sources

Available Tools

5 tools
check_program_eligibilityCheck program eligibilityA

Run the full deterministic SNAP financial eligibility test for a household. Returns the decision PLUS the rule trace and the policy citation behind every rule that fired, plus the ruleset version -- never a bare yes/no. Requires the caseworker scope. 'program' must be 'SNAP'.

ParametersJSON Schema
NameRequiredDescriptionDefault
programYes
householdYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
programYes
summaryYes
computedYes
decisionYes
citationsYes
rule_traceYes
pii_includedNo
household_sizeYes
ruleset_versionYes
determination_idYes

TDQS

A4.4/5.0
Behavior4/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure. It discloses that the operation is deterministic, returns a decision plus rule trace, policy citation, and ruleset version, and explicitly states it never gives a bare yes/no. It also states the required scope and program constraint. This is strong transparency, though it could mention potential error behavior or side effects (e.g., whether it modifies anything), but for a test/calculation tool, the lack of side effects is implied.

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

Conciseness5/5

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

The description is three sentences, with the central action in the first sentence, return behavior in the second, and constraints in the third. Every sentence adds value with no redundancy or fluff. It's front-loaded and efficiently structured.

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

Completeness4/5

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

Given the complexity of a full eligibility test with many household fields, the description is complete enough: it explains what the tool does, what it returns, the required scope, and the program constraint. The detailed household schema covers the input structure, and the presence of an output schema means return format need not be explained. It could be more explicit about how this relates to sibling tools, but the core context for using the tool correctly is present.

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

Parameters4/5

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

The top-level schema has no descriptions (0% coverage), so the description must compensate. It adds critical semantics for the 'program' parameter by stating it must be 'SNAP'. For 'household', the description implies it's the household to test, and the rich nested schema already provides detailed per-field descriptions. The description adds essential constraint and context that the schema lacks, making it more than a simple baseline.

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 description clearly states the tool runs a full deterministic SNAP financial eligibility test for a household, which is a specific verb+resource. It also distinguishes itself from siblings by emphasizing it returns a rule trace and policy citations, not a bare yes/no, and is SNAP-specific. This is a precise, well-defined purpose.

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

Usage Guidelines4/5

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

The description provides clear context: it's for a full SNAP eligibility test, requires the caseworker scope, and mandates that 'program' be 'SNAP'. It implicitly differentiates from siblings like screen_programs (by being 'full' and 'deterministic') and explain_determination (by producing its own trace). However, it does not explicitly state when NOT to use it or direct users to alternatives for simpler screening, so it falls just short of a 5.

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

explain_determinationExplain determinationA

Return a plain, step-by-step trace of a prior determination by its id: which rules fired, what they saw, and the citation behind each. Requires the caseworker scope. Use the determination_id returned by check_program_eligibility.

ParametersJSON Schema
NameRequiredDescriptionDefault
determination_idYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
stepsYes
programYes
summaryYes
decisionYes
ruleset_versionYes
determination_idYes

TDQS

A4.5/5.0
Behavior4/5

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

With no annotations, the description carries the transparency burden. It discloses a permission requirement (caseworker scope) and describes the output style (plain, step-by-step). It doesn't mention side effects, but the nature of 'explain' implies read-only behavior, which is acceptable.

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

Conciseness5/5

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

Two sentences with no wasted words. The purpose is front-loaded, and each sentence adds essential information (what it does, prerequisite, source of ID).

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?

Given the tool's simplicity (one parameter, output schema present), the description covers purpose, usage, permissions, and integration guidance. The existence of an output schema means return values need not be described.

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

Parameters4/5

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

The schema has no description for determination_id, and schema coverage is 0%. The description compensates by explaining the parameter is a prior determination id returned by check_program_eligibility, giving practical provenance and usage context.

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 description uses a specific verb 'Return' with a clear resource 'a plain, step-by-step trace of a prior determination' and lists what the trace contains (rules fired, inputs, citations). This clearly distinguishes it from siblings like check_program_eligibility.

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

Usage Guidelines4/5

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

The description states the prerequisite (caseworker scope) and instructs the user to use the determination_id from check_program_eligibility, which implies when to use this tool. It doesn't explicitly contrast with alternatives but provides strong contextual guidance.

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

list_required_verificationsList required verificationsA

List the documents a caseworker must verify to confirm SNAP eligibility for a household, derived from the facts the household presents (earned income implies pay stubs, shelter costs imply a lease, and so on). Requires the caseworker scope.

ParametersJSON Schema
NameRequiredDescriptionDefault
programYes
householdYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
programYes
verificationsYes
household_sizeYes

TDQS

A4.2/5.0
Behavior4/5

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

Without annotations, the description carries the transparency burden. It adds meaningful behavioral context beyond the schema: the tool derives verifications from household facts (e.g., earned income implies pay stubs, shelter costs imply a lease) and states the authorization requirement ('Requires the caseworker scope'). It does not explicitly mention read-only status or error behavior, but the 'List' verb and output schema mitigate this.

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

Conciseness5/5

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

The description is two sentences, front-loaded with the core purpose, and zero redundant or filler content. Examples are concise and illustrate behavior effectively. Every clause earns its place.

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

Completeness4/5

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

The tool has a complex nested household schema and an output schema, which reduces the need for the description to explain return values. The description covers the core purpose, derivation logic, and a permission constraint, making it complete enough for an agent to select and invoke the tool. The only notable gap is parameter guidance for 'program', but overall context is solid.

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

Parameters3/5

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

The description adds some semantic value by linking household facts (earned income, shelter costs) to expected verifications, which helps an agent understand how the household parameter is used. However, it does not describe the 'program' parameter's allowed values or format, and the schema description coverage for top-level parameters is 0%, leaving the program field ambiguous. The household structure is well-documented in the schema, so the description's contribution is moderate.

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 description uses a specific verb ('List') and a clear resource ('the documents a caseworker must verify to confirm SNAP eligibility for a household'). It also distinguishes from sibling tools by focusing on documents/verifications rather than program screening, eligibility checking, or policy lookup.

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

Usage Guidelines4/5

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

The description provides clear context for when to use the tool (when needing required verifications for a SNAP household based on presented facts) and includes an exclusion ('Requires the caseworker scope'). It does not name alternative tools explicitly, but the purpose is distinct enough that an agent can infer when to choose it.

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

lookup_policyLook up policyA

Answer a SNAP policy question with citations to the eligibility manual. Delegates to the policy-manual-rag retrieval index. Currently a stub that returns an explicit placeholder rather than an invented answer. Available to the screening scope.

ParametersJSON Schema
NameRequiredDescriptionDefault
questionYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
stubYes
answerYes
sourceYes
questionYes
citationsYes

TDQS

A4.2/5.0
Behavior4/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure. It transparently states the tool is currently a stub and that it returns an explicit placeholder rather than an invented answer, which is critical for an AI agent to avoid hallucination. It also mentions delegation to a RAG index, adding useful mechanism context.

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

Conciseness5/5

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

The description is concise with three sentences, each providing distinct value: purpose, mechanism, and current stub behavior. It is front-loaded with the primary purpose and contains no filler or redundant information.

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

Completeness4/5

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

Given the tool's simplicity (one parameter, output schema present), the description covers the essential aspects: purpose, delegation, and the stub limitation. It sufficiently sets expectations for an agent, though it could optionally clarify the difference from eligibility-checking tools.

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

Parameters3/5

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

The only parameter is 'question' with schema coverage at 0%, so the description must compensate. It adds that the question should be a SNAP policy question, which gives some context, but does not provide examples, formatting, or guidance on question complexity. This is adequate but not highly informative.

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 description clearly states the tool answers SNAP policy questions with citations to the eligibility manual, using a specific verb ('answer') and a specific resource. This distinguishes it from sibling tools like screen_programs and check_program_eligibility, which focus on screening and eligibility determination.

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

Usage Guidelines4/5

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

The description provides clear context for when to use the tool: for SNAP policy questions, via the policy-manual-rag retrieval index. It also importantly discloses that the tool is currently a stub returning a placeholder, which sets expectations. It does not explicitly name alternative tools, but the context is strong enough.

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

screen_programsScreen programsA

Coarse, anonymous-safe screen of a household across SNAP and a simplified Medicaid income check. Returns a 'likely eligible' signal per program with a citation. This is NOT a determination and stores no data. Available to the screening scope. For a real determination, use check_program_eligibility.

ParametersJSON Schema
NameRequiredDescriptionDefault
householdYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
screensYes
disclaimerYes
household_sizeYes

TDQS

A4.3/5.0
Behavior4/5

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

With no annotations, the description carries the full burden and does well: it discloses that the tool is anonymous-safe, stores no data, and is not a determination. This goes beyond a simple read/write hint. It doesn't mention rate limits or detailed side effects, but for a screening tool these are the key behavioral traits.

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

Conciseness5/5

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

Two sentences: the first is a punchy core definition, the second add essential caveats and the alternative tool. Every sentence earns its place, and the key info is front-loaded.

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

Completeness4/5

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

Given the moderate complexity of screening two programs, the description covers purpose, scope, safety, and alternatives. An output schema likely covers the return value details. It doesn't explain what 'citation' means or how to interpret the 'likely eligible' signal, but this is reasonable given the output schema exists.

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

Parameters2/5

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

The tool description makes no mention of the single 'household' parameter, and schema description coverage is 0%, so it fails to compensate. The input schema itself has detailed definitions for Household and its fields, but the description adds no guidance on how to construct the input or what is expected beyond what the schema already provides.

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 description clearly states the tool screens a household across SNAP and simplified Medicaid, returning a 'likely eligible' signal per program. It distinguishes itself from check_program_eligibility by explicitly labeling this as a non-determination screening, which sets it apart from the sibling tool.

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?

The description explicitly says 'This is NOT a determination' and directs users to check_program_eligibility for real determinations. It also mentions 'Available to the screening scope', which clarifies when this tool should be used (initial screening without data storage).

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

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.

  1. 5 tool updatesv0.1.0
    • First observedcheck_program_eligibility
    • First observedexplain_determination
    • First observedlist_required_verifications
    • First observedlookup_policy
    • First observedscreen_programs

TDQS

A4.5/5.0
Disambiguation5/5

Each tool serves a distinct purpose: screening, full eligibility check, required verifications, explaining prior determinations, and policy lookup. The descriptions explicitly differentiate between screening and the full determination, preventing confusion.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern: screen_programs, check_program_eligibility, list_required_verifications, explain_determination, lookup_policy. The verbs are descriptive and the style is uniform.

Tool Count5/5

With 5 tools, the server is well-scoped for a rules-as-code domain focused on SNAP eligibility. Each tool fills a necessary role in the workflow without redundancy or bloat.

Completeness5/5

The tool set covers the full eligibility life cycle: screening, detailed determination, verification document list, explanation of past results, and policy lookup. The workflow is end-to-end and there are no obvious missing operations.

Maintenance

ActivityStale
ResponsivenessSyncing

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    B
    maintenance
    24 free personal-finance and macro tools (mortgage, paycheck, tax, FRED, BLS) for LLM agents. Zero API keys, stdio transport, source-cited from IRS, Federal Reserve, BLS, Treasury, and Freddie Mac.
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    Provides retirement planning computations for AI agents, including Monte Carlo simulations, tax burden modeling across all US states, Social Security claiming optimization, and cost-of-living comparisons.
    7
    MIT

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/adamselzer/rules-as-code-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server