Skip to main content
Glama
northernvariables

FedMCP - Federal Parliamentary Information

README.mdโ€ข17.7 kB
# CanadaGPT GraphQL API High-performance GraphQL API for Canadian government accountability data. Built with GraphQL Yoga, @neo4j/graphql, and Neo4j Aura. --- ## ๐Ÿ“‹ Overview This GraphQL API provides: **Parliamentary Data:** - MPs, parties, ridings - Bills, votes, debates, committees - Petitions **Financial Transparency:** - MP quarterly expenses - Government contracts - Grants and contributions - Political donations **Lobbying & Influence:** - Lobbying registrations - Communication logs (lobbyist-government meetings) - Corporate influence mapping **Legal Data:** - Supreme Court and Federal Court cases - Legislation citations **Accountability Analytics:** - MP performance scorecards - Conflict of interest detection - Money flow tracing - Top spenders analysis --- ## ๐Ÿš€ Quick Start ### Installation ```bash cd packages/graph-api # Install dependencies npm install # Copy environment variables cp .env.example .env # Edit with your Neo4j credentials nano .env ``` ### Configuration **.env file:** ```bash NEO4J_URI=neo4j+s://xxxxx.databases.neo4j.io NEO4J_USER=neo4j NEO4J_PASSWORD=your_password_from_phase_1_2 PORT=4000 NODE_ENV=development CORS_ORIGINS=http://localhost:3000 GRAPHQL_INTROSPECTION=true GRAPHQL_PLAYGROUND=true ``` ### Development ```bash # Start dev server with hot reload npm run dev # Server starts at http://localhost:4000/graphql ``` **Expected output:** ``` โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๐Ÿ‡จ๐Ÿ‡ฆ CanadaGPT GraphQL API โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๐Ÿ” Validating configuration... Neo4j URI: neo4j+s://xxxxx.databases.neo4j.io Server Port: 4000 โœ… Configuration valid ๐Ÿ”Œ Connecting to Neo4j... โœ… Connected to Neo4j 5.16.0 (Enterprise) ๐Ÿ“Š Database Statistics: Nodes: 7,338 Relationships: 2,000 Node Types: 6 Relationship Types: 2 โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๐Ÿš€ CanadaGPT GraphQL API โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ๐Ÿ“ก Server running at http://0.0.0.0:4000/graphql ๐ŸŽฎ GraphiQL: http://localhost:4000/graphql ๐ŸŒ Environment: development โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ•โ• ``` ### Production Build ```bash # Build TypeScript to JavaScript npm run build # Start production server npm start ``` --- ## ๐Ÿ” GraphQL Schema ### Auto-Generated CRUD Operations The `@neo4j/graphql` library auto-generates queries and mutations for all node types: **Queries:** - `mPs(where, options)` - List MPs with filtering and pagination - `mP(where)` - Get single MP - `bills(where, options)` - List bills - `votes(where, options)` - List votes - `lobbyRegistrations(where, options)` - List lobbying registrations - ... (all node types) **Filters:** ```graphql where: { name: "Pierre Poilievre" # Exact match name_CONTAINS: "Pierre" # Contains name_STARTS_WITH: "P" # Starts with current: true # Boolean elected_date_GTE: "2015-10-19" # Greater than or equal party_IN: ["Conservative", "Liberal"] # In list AND: [...] # Logical AND OR: [...] # Logical OR } ``` **Options:** ```graphql options: { limit: 10 # Pagination offset: 0 sort: [{ name: ASC }] # Sorting } ``` --- ## ๐Ÿ“– Example Queries ### 1. List MPs with Party and Riding ```graphql query ListMPs { mPs( where: { current: true } options: { limit: 10, sort: [{ name: ASC }] } ) { id name party riding elected_date memberOf { name code seats } represents { name province } } } ``` **Response:** ```json { "data": { "mPs": [ { "id": "pierre-poilievre", "name": "Pierre Poilievre", "party": "Conservative", "riding": "Carleton", "elected_date": "2004-06-28", "memberOf": { "name": "Conservative Party of Canada", "code": "CPC", "seats": 118 }, "represents": { "name": "Carleton", "province": "Ontario" } } // ... 9 more MPs ] } } ``` --- ### 2. Get MP with Sponsored Bills ```graphql query GetMPWithBills { mPs(where: { name: "Pierre Poilievre" }) { name party sponsored { number session title status introduced_date } } } ``` --- ### 3. MP Performance Scorecard (Custom Query) ```graphql query MPScorecard { mpScorecard(mpId: "pierre-poilievre") { mp { name party riding } bills_sponsored bills_passed votes_participated petitions_sponsored total_petition_signatures current_year_expenses lobbyist_meetings legislative_effectiveness } } ``` **Response:** ```json { "data": { "mpScorecard": { "mp": { "name": "Pierre Poilievre", "party": "Conservative", "riding": "Carleton" }, "bills_sponsored": 12, "bills_passed": 3, "votes_participated": 487, "petitions_sponsored": 5, "total_petition_signatures": 125000, "current_year_expenses": 342567.89, "lobbyist_meetings": 23, "legislative_effectiveness": 25.0 } } } ``` --- ### 4. Search Bills by Keyword ```graphql query SearchBills { bills( where: { title_CONTAINS: "climate" status_IN: ["Passed", "In Committee"] } options: { limit: 5, sort: [{ introduced_date: DESC }] } ) { number session title status sponsor { name party } introduced_date } } ``` --- ### 5. Top Spenders (Custom Query) ```graphql query TopSpenders { topSpenders(fiscalYear: 2025, limit: 10) { mp { name party riding } total_expenses } } ``` --- ### 6. Bill Lobbying Activity ```graphql query BillLobbying { billLobbying(billNumber: "C-11", session: "44-1") { bill { title status } organizations_lobbying total_lobbying_events organizations { name industry lobbying_count } } } ``` **Use Case:** "Which corporations are lobbying on Bill C-11?" --- ### 7. Detect Conflicts of Interest ```graphql query ConflictsOfInterest { conflictsOfInterest(limit: 20) { mp { name party } organization { name industry } bill { number title } suspicion_score } } ``` **What it detects:** 1. Organization lobbied on a bill 2. Same organization donated to MP's party 3. MP voted "yea" on that bill 4. Same organization received government contracts **Suspicion score:** Number of times this pattern occurred --- ### 8. Trace Money Flow ```graphql query MoneyFlow { organizations( where: { name_CONTAINS: "SNC" } ) { name # Lobbying activity lobbiedOn { number title } # Political donations donated { name code } # Contracts received receivedContracts(options: { limit: 5, sort: [{ amount: DESC }] }) { amount date department description } } } ``` **Use Case:** "Show me all financial connections for SNC-Lavalin" --- ## ๐Ÿ—๏ธ Architecture ### Technology Stack **GraphQL Server:** - `graphql-yoga` - Modern GraphQL server (HTTP streaming, subscriptions) - `@neo4j/graphql` - Auto-generates resolvers from Neo4j schema - `neo4j-driver` - Official Neo4j database driver **Type Safety:** - TypeScript 5.3 - Full type inference from GraphQL schema **Performance:** - Connection pooling (max 50 connections) - Automatic query optimization by @neo4j/graphql - Neo4j Aura indexes (Phase 1.3) --- ### Request Flow ``` โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Client (Frontend) โ”‚ โ”‚ http://localhost:3000 โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ GraphQL Query โ–ผ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ GraphQL Yoga Server โ”‚ โ”‚ http://localhost:4000/graphql โ”‚ โ”‚ โ”‚ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ โ”‚ โ”‚ @neo4j/graphql (Schema โ†’ Cypher) โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ GraphQL Query โ†’ Cypher Query โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ query GetMP { MATCH (m:MP {id: ...}) โ”‚ โ”‚ โ”‚ โ”‚ mPs(where: {id: "..."}) RETURN m โ”‚ โ”‚ โ”‚ โ”‚ } โ”‚ โ”‚ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚ Cypher Query โ–ผ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ Neo4j Aura (Database) โ”‚ โ”‚ neo4j+s://xxxxx.databases.neo4j.io โ”‚ โ”‚ โ”‚ โ”‚ 1.6M Nodes โ”‚ 10M Relationships โ”‚ 17 Constraints โ”‚ 23 Indexesโ”‚ โ”‚ โ”‚ โ”‚ MPs โ”€โ”€โ”€โ”€MEMBER_OFโ”€โ”€โ”€โ”€> Parties โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ””โ”€โ”€VOTEDโ”€โ”€โ”€> Votes โ”€โ”€SUBJECT_OFโ”€โ”€> Bills โ”‚ โ”‚ โ”‚ โ”‚ Organizations โ”€โ”€LOBBIED_ONโ”€โ”€> Bills โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ ``` --- ### Custom Resolvers (@cypher directive) For complex accountability queries, we use `@cypher` directives: **Example:** ```graphql type Query { mpScorecard(mpId: ID!): MPScorecard @cypher( statement: """ MATCH (mp:MP {id: $mpId}) OPTIONAL MATCH (mp)-[:SPONSORED]->(bill:Bill) RETURN { mp: mp, bills_sponsored: count(DISTINCT bill), bills_passed: count(DISTINCT bill {status: 'Passed'}) } """ columnName: "scorecard" ) } ``` **Why @cypher?** - Performance: Single database roundtrip - Flexibility: Full Cypher query power - Maintainability: Queries defined in schema --- ## ๐Ÿ”’ Security ### Authentication (TODO Phase 6) Currently, the API is **open** for development. Production deployment will add: **JWT Authentication:** ```graphql type Mutation { login(email: String!, password: String!): AuthToken } type AuthToken { token: String! expiresAt: DateTime! } ``` **Authorization Rules:** ```graphql type MP @node @authorization(filter: [{ where: { node: { current: true } } }]) { # Only show current MPs to public } ``` ### Rate Limiting (TODO Phase 6) **Cloud Run + Cloud Armor:** - 100 requests/min per IP - 1000 requests/min per API key ### CORS **Development:** ```bash CORS_ORIGINS=http://localhost:3000,http://localhost:5173 ``` **Production:** ```bash CORS_ORIGINS=https://canadagpt.ca,https://www.canadagpt.ca ``` --- ## ๐Ÿงช Testing ### Manual Testing (GraphiQL) ```bash # Start dev server npm run dev # Open browser open http://localhost:4000/graphql ``` Use the built-in GraphiQL explorer to test queries. --- ### Automated Testing (TODO) ```bash # Unit tests npm test # Integration tests (requires Neo4j) npm run test:integration ``` --- ## ๐Ÿš€ Deployment (Phase 3.2) ### Docker Build ```bash # Build image docker build -t canadagpt-api:latest . # Run locally docker run -p 4000:4000 \ -e NEO4J_URI=neo4j+s://xxxxx.databases.neo4j.io \ -e NEO4J_PASSWORD=your_password \ canadagpt-api:latest ``` --- ### Cloud Run Deployment ```bash # Build and push to Artifact Registry gcloud builds submit --tag us-central1-docker.pkg.dev/PROJECT_ID/canadagpt/api:latest # Deploy to Cloud Run gcloud run deploy canadagpt-api \ --image us-central1-docker.pkg.dev/PROJECT_ID/canadagpt/api:latest \ --region us-central1 \ --platform managed \ --vpc-connector canadagpt-vpc-connector \ --service-account canadagpt-api@PROJECT_ID.iam.gserviceaccount.com \ --set-secrets NEO4J_PASSWORD=neo4j-password:latest \ --set-env-vars NEO4J_URI=neo4j+s://xxxxx.databases.neo4j.io \ --set-env-vars NODE_ENV=production \ --min-instances 1 \ --max-instances 10 \ --cpu 1 \ --memory 512Mi \ --timeout 60s \ --no-allow-unauthenticated ``` **Why these flags:** - `--vpc-connector`: Connects to Neo4j Aura via Private Service Connect - `--service-account`: Uses IAM for Neo4j password access - `--set-secrets`: Loads password from Secret Manager - `--min-instances 1`: Always-on for low latency - `--no-allow-unauthenticated`: Requires authentication (frontend โ†’ API internal call) --- ## ๐Ÿ“Š Performance ### Query Performance **Simple queries (single node):** - Latency: 10-50ms - Throughput: 500 req/sec **Complex queries (MP scorecard with 5 relationships):** - Latency: 50-200ms - Throughput: 100 req/sec **Full-text search:** - Latency: 100-500ms - Throughput: 50 req/sec **Optimizations:** - โœ… Neo4j indexes (Phase 1.3) - โœ… Connection pooling (50 connections) - โœ… Auto-generated efficient Cypher by @neo4j/graphql - ๐Ÿšง Response caching (TODO Phase 7) --- ### Monitoring (Phase 7) **Cloud Run Metrics:** - Request latency (p50, p95, p99) - Error rate - Container CPU/memory usage **Neo4j Aura Metrics:** - Query execution time - Connection pool usage - Database size --- ## ๐Ÿ› Troubleshooting ### Issue: "Connection refused" to Neo4j **Cause:** Neo4j Aura requires VPC Connector in Cloud Run **Fix (Development):** - Use Neo4j Aura public endpoint temporarily - Enable "Public access" in Aura console - Add your IP to allowlist **Fix (Production):** - Deploy to Cloud Run with `--vpc-connector` flag - Use Private Service Connect endpoint from Phase 1.2 --- ### Issue: "Authentication failed" **Cause:** Wrong NEO4J_PASSWORD **Fix:** ```bash # Get password from Secret Manager gcloud secrets versions access latest --secret="neo4j-password" # Update .env NEO4J_PASSWORD=correct_password_here ``` --- ### Issue: GraphQL query returns empty array **Cause:** No data in Neo4j (Phase 2.2 not run yet) **Fix:** ```bash # Run parliament data ingestion cd ../data-pipeline canadagpt-ingest --parliament # Verify data loaded canadagpt-ingest --test ``` --- ## ๐Ÿ“ File Structure ``` packages/graph-api/ โ”œโ”€โ”€ package.json โœ… Dependencies and scripts โ”œโ”€โ”€ tsconfig.json โœ… TypeScript configuration โ”œโ”€โ”€ .env.example โœ… Environment variable template โ”œโ”€โ”€ README.md โœ… This file โ”œโ”€โ”€ Dockerfile โณ Docker build (Phase 3.2) โ”‚ โ””โ”€โ”€ src/ โ”œโ”€โ”€ index.ts โœ… Entry point (194 lines) โ”œโ”€โ”€ config.ts โœ… Configuration management (53 lines) โ”œโ”€โ”€ neo4j.ts โœ… Neo4j driver (105 lines) โ”œโ”€โ”€ server.ts โœ… GraphQL Yoga setup (147 lines) โ””โ”€โ”€ schema.ts โœ… GraphQL schema (500+ lines) Total: ~1,000 lines of TypeScript ``` --- ## ๐ŸŽฏ Next Steps **Phase 3.2: Deploy to Cloud Run** - Create Dockerfile - Build and push Docker image to Artifact Registry - Deploy to Cloud Run with VPC Connector - Test from frontend **Phase 4: Frontend Development** - Next.js 15 with App Router - Apollo Client for GraphQL - Use design system from Phase 1.1 - Key pages: Landing, Dashboard, MP profile, Bill details **Phase 7: Monitoring & Optimization** - Response caching (Redis) - Query performance monitoring - Error tracking (Sentry) --- **GraphQL API is ready for local development! Next: Deploy to Cloud Run**

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/northernvariables/FedMCP'

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