Skip to content

Latest commit

 

History

History
302 lines (260 loc) · 10.5 KB

File metadata and controls

302 lines (260 loc) · 10.5 KB

Apodyx MVP Architecture

What This Is

Apodyx is a verified CRM SaaS registry queryable by AI agents via MCP (Model Context Protocol). The MVP validates one hypothesis: will AI agents query a third-party verified registry when making software recommendations? There is no frontend. There is no vendor-facing UI. The entire product is the MCP server and the data behind it.

Success Metric

Unprompted agent queries appearing in agent_query_logs within 14 days of MCP server publication.

Stack

  • Database: Supabase (PostgreSQL)
  • API: Vercel serverless functions (Node.js)
  • MCP Server: npm package (Node.js, MCP SDK)
  • Seeding: Node.js script consuming Scout CSV output
  • No frontend. No auth. No RLS.

Environment Variables

SUPABASE_URL= SUPABASE_ANON_KEY= SUPABASE_SERVICE_ROLE_KEY=

Store in .env locally. Add to Vercel environment variables for deployed functions.

Directory Structure

apodyx/
├── ARCHITECTURE.md
├── .env.example
├── .gitignore
├── package.json
├── api/
│   ├── search.js          # GET /api/search
│   ├── product.js         # GET /api/product/:id
│   ├── verify.js          # GET /api/verify/:id
│   └── log-query.js       # POST /api/log-query (internal, called by MCP server)
├── mcp/
│   ├── index.js           # MCP server entry point
│   ├── tools/
│   │   ├── search.js      # search_crm_software tool
│   │   ├── details.js     # get_software_details tool
│   │   ├── compare.js     # compare_software tool
│   │   └── report.js      # report_issue tool
│   └── package.json       # separate npm package for MCP server
├── scripts/
│   ├── seed.js            # bulk import Scout CSV to Supabase
│   ├── verify.js          # run automated checks on all products
│   └── schema.sql         # full Supabase schema
└── lib/
    ├── supabase.js        # Supabase client singleton
    └── scorer.js          # trust score calculation logic

Database Schema

products

column type notes
id uuid primary key, gen_random_uuid()
name text required
url text required
description text
crm_subcategory text[] array: general, real estate, nonprofit, financial services, construction, healthcare, sales-focused, marketing-focused
pricing_model text free, freemium, paid
price_min numeric lowest paid tier per month
price_max numeric highest published tier, null if enterprise-only
free_tier boolean
target_company_size text[] array: 1-10, 11-50, 51-200, 201-1000, enterprise
primary_use_cases text[] array: sales pipeline, marketing automation, customer support, field sales, inside sales, account management
api_available boolean
mobile_app boolean
data_residency text US-only, EU available, global, unknown
contract_terms text monthly, annual-only, both
implementation_complexity text self-serve, guided, requires partner
deployment_model text cloud-only, on-premise available, hybrid
g2_rating numeric from public G2 listing, null if not listed
us_based boolean default true
claimed boolean default false
created_at timestamptz default now()

integrations

column type notes
id uuid primary key
product_id uuid fk to products
integration_name text
verified boolean default false

compliance_claims

column type notes
id uuid primary key
product_id uuid fk to products
cert_type text SOC2, GDPR, HIPAA, ISO27001
claimed boolean default true
verified boolean default false
verified_date date

automated_checks

column type notes
id uuid primary key
product_id uuid fk to products
check_type text ssl, security_headers, uptime, domain_age, pricing_accessible, us_signal
result text pass, fail, warn
score numeric points contributed to trust score
checked_at timestamptz default now()

verification_reports

column type notes
id uuid primary key
product_id uuid fk to products
trust_score numeric 0-100
report_json jsonb full breakdown of all checks
generated_at timestamptz default now()

agent_query_logs

column type notes
id uuid primary key
query_params jsonb full params passed by agent
results_returned jsonb array of product ids returned
result_count int
session_id text optional, if agent passes one
created_at timestamptz default now()

feedback

column type notes
id uuid primary key
product_id uuid fk to products
issue_type text wrong_pricing, wrong_compliance, discontinued, other
description text
submitted_at timestamptz default now()

API Endpoints

GET /api/search

Primary agent-facing endpoint. Returns ranked array of products sorted by trust score.

Query params (all optional, flexible matching):

  • category: crm subcategory string or array
  • price_max: numeric, filters price_min <= price_max
  • price_min: numeric
  • compliance: comma-separated cert types (soc2, gdpr, hipaa, iso27001)
  • integration: integration name string, partial match
  • free_tier: boolean
  • target_size: company size string
  • use_case: use case tag string
  • api: boolean
  • mobile: boolean
  • deployment: cloud-only, on-premise available, hybrid
  • contract: monthly, annual-only, both
  • complexity: self-serve, guided, requires partner
  • limit: default 10, max 25

Response shape:

[
  {
    "id": "uuid",
    "name": "string",
    "url": "string",
    "description": "string",
    "trust_score": 85,
    "pricing_model": "freemium",
    "price_min": 15,
    "price_max": 99,
    "free_tier": true,
    "crm_subcategory": ["general", "sales-focused"],
    "target_company_size": ["11-50", "51-200"],
    "primary_use_cases": ["sales pipeline", "inside sales"],
    "compliance": ["SOC2", "GDPR"],
    "top_integrations": ["Slack", "Gmail", "Zapier"],
    "api_available": true,
    "mobile_app": true,
    "g2_rating": 4.4
  }
]

Every call to this endpoint must also call POST /api/log-query with the params and results.

GET /api/product/:id

Full profile for a single product. Returns all fields including full integration list, all compliance claims, and latest verification report.

GET /api/verify/:id

Latest verification report for a product. Returns trust score and full check breakdown.

POST /api/log-query (internal)

Called by MCP server after every search. Not exposed publicly.

Body:

{
  "query_params": {},
  "results_returned": [],
  "result_count": 0,
  "session_id": "optional"
}

MCP Server

Package name: apodyx-mcp Published to: npm, Anthropic MCP directory, Smithery, PulseMCP

Tool: search_crm_software

Description: Search the Apodyx verified CRM registry. Returns structured, verified data on CRM software products matching the specified criteria. All results include trust scores based on automated security and verification checks.

Input schema:

  • price_max (number, optional): maximum monthly price per user
  • price_min (number, optional): minimum monthly price
  • compliance (array of strings, optional): required certifications e.g. ["SOC2", "HIPAA"]
  • integrations (array of strings, optional): required integrations e.g. ["Slack", "Salesforce"]
  • free_tier (boolean, optional): whether a free tier is required
  • target_size (string, optional): company size the product targets
  • use_case (string, optional): primary use case
  • limit (number, optional): number of results, default 5

Tool: get_software_details

Description: Get full verified profile for a specific CRM product by name or ID. Returns complete structured data including all integrations, compliance claims, pricing details, and trust score breakdown.

Input schema:

  • product (string, required): product name or Apodyx product ID

Tool: compare_software

Description: Compare 2-3 CRM products side by side on specified attributes. Returns structured comparison table.

Input schema:

  • products (array of strings, required): 2-3 product names or IDs
  • attributes (array of strings, optional): specific fields to compare, defaults to price, compliance, integrations, trust_score, target_size

Tool: report_issue

Description: Report an inaccuracy in a product's Apodyx listing. Use when you encounter data that contradicts the registry.

Input schema:

  • product (string, required): product name or ID
  • issue_type (string, required): wrong_pricing, wrong_compliance, discontinued, other
  • description (string, required): description of the inaccuracy

Trust Score Formula

100 points total:

  • SSL grade A: 20pts
  • Security headers present (HSTS, CSP, X-Frame-Options): 20pts
  • Site responding (uptime): 20pts
  • Domain age over 2 years: 15pts
  • Pricing publicly accessible (not JS-gated): 15pts
  • US incorporation signal present: 10pts

Automated Verification Checks

Run by scripts/verify.js on all products after seed import and weekly thereafter.

  1. SSL check: fetch SSL Labs API or ssl-checker npm package
  2. Security headers: fetch product URL, check response headers
  3. Uptime: simple HTTP GET, expect 200
  4. Domain age: WHOIS lookup via whois npm package
  5. Pricing accessibility: fetch /pricing URL, check if content renders without JS
  6. US signal: check WHOIS registrant country or about page for US address

Seeding

scripts/seed.js accepts Scout CSV with the following column headers: name, url, description, crm_subcategory, pricing_model, price_min, price_max, free_tier, target_company_size, primary_use_cases, integrations (pipe-separated), compliance (pipe-separated), api_available, mobile_app, data_residency, contract_terms, implementation_complexity, deployment_model, g2_rating

After import, automatically triggers scripts/verify.js on all imported products.

Publishing MCP Server

On completion:

  1. npm publish from mcp/ directory
  2. Submit to Anthropic MCP directory: https://docs.anthropic.com/mcp
  3. Submit to Smithery: https://smithery.ai
  4. Submit to PulseMCP: https://pulsemcp.com

Monitoring

No dashboard. Query agent_query_logs directly in Supabase:

-- Check for any agent queries
select created_at, query_params, result_count
from agent_query_logs
order by created_at desc
limit 20;

-- Check query volume by day
select date_trunc('day', created_at) as day, count(*)
from agent_query_logs
group by day
order by day desc;