44 documents
Integrations & APIs⏱️6 min read

MCP server — the Agentic Action Layer

Verified against this repository on 2026-07-30. Variable **names** only — never values.

MCP server — the Agentic Action Layer

Verified against this repository on 2026-07-30. Variable names only — never values.

This is the action layer that ../strategy/positioning.md calls the core differentiator, the MCP half of Tier 2 in ../sales/pricing-tiers.md, and Step 2 of the live demo (../sales/demo-framework.md). It is live on JSGlobtech's own site, which is what makes the demo real.

Decision record: ../decisions/0003-lead-capture-via-mcp-and-openapi.md.

Endpoint

Item Detail
Route file app/api/mcp/[transport]/route.ts
Handler handleMcpHttpRequest in lib/mcp-server.ts
Accepted transport values sse, mcp — anything else returns 404 not_found with a message naming the valid paths
Canonical agent URL https://jsglobtech.com/api/mcp/sse
Alternate path https://jsglobtech.com/api/mcp/mcp
Methods GET, POST, DELETE, OPTIONS
Runtime nodejs, maxDuration = 60
SDK @modelcontextprotocol/sdk ^1.29.0
Transport class WebStandardStreamableHTTPServerTransport
Session mode Stateless — sessionIdGenerator: undefined, enableJsonResponse: true

Despite the sse path name, both paths run the same Streamable HTTP handler. sse is kept because it is the URL commonly advertised to and expected by MCP clients; there is no separate legacy SSE implementation.

Statelessness

A fresh McpServer and transport are constructed per request, connected, used, then closed in a finally block. No Redis, no session store, no shared memory. This is deliberate: it works on serverless and multi-instance deployments where consecutive requests may land on different instances. Modern MCP clients POST initialize to the advertised URL and do not require session continuity.

Trade-off: per-request construction costs a little latency, and any future feature needing cross-call state (progress notifications, long-running subscriptions) would require revisiting this.

CORS

Set in lib/mcp-server.ts and applied to every response via withCors:

  • Access-Control-Allow-Origin: *
  • Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS
  • Access-Control-Allow-Headers: Content-Type, Accept, Authorization, Mcp-Session-Id, Last-Event-ID
  • Access-Control-Expose-Headers: Mcp-Session-Id

OPTIONS short-circuits to 204 before any server is constructed. The endpoint is intentionally unauthenticated and public — it exists so arbitrary AI hosts can reach it.

Server identity

createJsGlobtechMcpServer() registers an McpServer named jsglobtech-mcp, version 1.0.0.

Tool: request_dev_consultation

The only registered tool. Title: "Request JSGlobtech Dev Consultation".

Its description is written for model consumption and instructs the agent to collect client_name and client_email_or_phone before calling, and to prefer WhatsApp-ready UAE numbers. That prompt engineering is part of the product — it is what makes hosts behave well.

Input schema (Zod)

Field Type Required Notes
client_id string No Tenant key for webhook routing; defaults to default. Demo dogfood: jsglobtech.
client_name string, min 2 Yes Full name of the client or decision-maker
client_email_or_phone string, min 5 Yes Email or phone/WhatsApp; +971 encouraged for UAE
project_type enum Yes flutter_mobile_app | web_application | geo_ai_integration
budget_range_usd positive number or non-empty string Yes e.g. 15000, "10000-25000", "Not sure yet"
requirements_notes string No Goals, platforms, timeline, compliance, integrations

Result

On success the tool returns both content (pretty-printed JSON text) and structuredContent:

{ "ok": true, "lead_id": "jsg-<uuid>", "client_id": "…", "message": "…", "project_type": "…", "received_at": "<ISO-8601>" }

Error contract

Errors return isError: true with a JSON body rather than throwing, so the host can relay something useful to the user:

Cause error Behaviour
LeadValidationError validation_error Includes per-issue path and message so the agent can re-prompt for the missing field
LeadWebhookError webhook_error Tells the user the lead was validated but delivery failed, and offers the fallback email
Anything else internal_error Logged server-side as [mcp] request_dev_consultation failed

OpenAPI mirror (ChatGPT Actions / Claude webhooks)

Item Detail
Spec lib/openapi-spec.ts, served at /docs/openapi.json and /api/openapi.json (CORS Access-Control-Allow-Origin: *)
OpenAPI version 3.0.3
Title JSGlobtech Lead Capture API, version 1.0.0
Server https://jsglobtech.com (Production)
Path POST /api/leads/submit — the only path
operationId submitDevConsultationLead
Documented responses 200, 400, 500, 502
Component schemas ProjectType, ConsultationLeadRequest, ConsultationLeadSuccess, LeadError

The spec's info.description also carries agent instructions ("ask the user for any missing required fields. Do not invent contact details."), mirroring the MCP tool description.

Both surfaces converge on submitConsultationLead() in lib/leads.ts, differing only in the recorded source ("mcp" vs "openapi"). See ../integrations/lead-capture.md.

Discoverability

An agent can find all of this without documentation, which is the point of the GEO layer:

  • public/.well-known/llms.txt / public/llms.txt list the MCP endpoints, the OpenAPI URL, the REST endpoint, and the tool's full field contract.
  • components/GeoSchema.tsx publishes the MCP endpoint and OpenAPI definition as additionalProperty values on ProfessionalService, and a #software-mcp SoftwareApplication node whose url is the SSE endpoint and documentation is the OpenAPI URL.

Playbook claims not implemented here

The playbook attributes more to this layer than the code delivers. Recorded so nobody sells the gap:

Claim Source Reality
"book consultations" §1 Captures a lead. No calendar or scheduling integration.
"process reservations directly inside the chat" §1 No booking, reservation, or payment capability.
"Multi-endpoint MCP tools" §3 Tier 3 Exactly one tool; OpenAPI exposes exactly one path.
"Live Inventory/Property sync" §3 Tier 3 No database, ORM, or external data source in the repo.
"24/7 Hosting & Monitoring" §3 Tier 2 No monitoring, alerting, or uptime tooling present.
"Confirm / Submit button appears in the chat" §6 Step 2 Host-client UI, not JSGlobtech code. The tool returns JSON; approval UI varies by client.

Tier 3 items are buildable — they are ordinary integration work — but they are unbuilt, so quote them as engineering rather than as retainer inclusions.

Not used

  • No auth, API key, or rate limiting on the MCP endpoint (REST /api/leads/submit does rate-limit; MCP does not).
  • X-API-Key on REST is treated as a client_id, not real authentication — see ../operations/production-security-audit.md.
  • No Redis or session store (stateless by design).
  • No MCP resources or prompts registered — tools only.

Production security implications of the public MCP surface: ../operations/production-security-audit.md (findings #4, #5, #6 and related).