@ekoindia/eps-context-mcp
v0.1.40
Published
Local MCP server giving AI coding agents context for Eko Platform Services (EPS) APIs.
Readme
@ekoindia/eps-context-mcp
A local, stdio MCP server that gives AI coding agents accurate, up-to-date context for Eko Platform Services (EPS) APIs — endpoints, request/response shapes, auth, errors, pricing, environments, and multi-step integration recipes.
The full API bundle is baked into the package (works offline). No EPS account or credentials are needed to run it. The server exposes a small set of tiered, lazy, secret-free tools so an agent can list/search first and only fetch full detail when it needs it.
Install / run
No install step required — run it on demand with npx:
npx -y @ekoindia/eps-context-mcp@latestThe @latest tag makes npx re-resolve the newest published version on each
launch, so you always run the current server + API bundle without editing your
config (see Staying up to date).
The server speaks MCP over stdio, so it is meant to be launched by an MCP client (see per-harness config below) rather than run by hand. It logs its status to stderr and waits for an MCP client on stdin/stdout.
Requires Node.js ≥ 18.
Hosted (remote) server
The same tools are also served over streamable HTTP, with nothing to install:
https://mcp.eko.in/context/mcpNo auth, no key, no signup — every tool is a read-only lookup over the public API bundle. Use it when your agent cannot spawn a local process (claude.ai connectors, Lovable, other hosted agents), or when you would rather not manage a version at all: the hosted server re-validates the bundle against the live site, so it always answers from current docs.
# Claude Code, as a remote server
claude mcp add eps --transport http https://mcp.eko.in/context/mcpPOST only (per the MCP streamable-HTTP spec — the server keeps no session), and
GET https://mcp.eko.in/context/healthz reports the bundle version it is serving.
Rate-limited per IP at the proxy.
Non-MCP clients (REST + OpenAPI)
For tools that take plain HTTP actions instead of MCP — ChatGPT custom GPTs (Actions), Gemini function calling, n8n, Zapier and the like — the same tools are served as REST, described by a generated OpenAPI 3.1 document:
https://mcp.eko.in/context/openapi.jsonEvery tool is POST /context/tools/<name> with its arguments as a JSON object
body (empty body = no arguments). It is not a second implementation: each
request drives the real MCP server in-process, so names, arguments and
validation match the MCP tools exactly, and a new tool appears here
automatically (only tools annotated readOnlyHint: true are published).
curl -s -X POST https://mcp.eko.in/context/tools/get_faqs \
-H 'content-type: application/json' -d '{"query":"billing","limit":3}'200→ the tool's JSON result (non-JSON output such asget_signing_snippetcomes back as{ "text": "…" }).400→ invalid arguments or a body that is not a JSON object;404→ unknown tool, or the slug/id/recipe looked up does not exist;503→ bundle not loaded yet. Errors are{ "error": { "code", "message" } }.
ChatGPT custom GPT: Configure → Actions → Import from URL →
https://mcp.eko.in/context/openapi.json, authentication None.
stdio is still the better fit for CLI agents (Claude Code, Cursor, Codex): it starts instantly, works offline from the baked bundle, and costs no network round trip per tool call.
Tools
All tools are read-only and secret-free — none of them accept an
access_key or any other credential. Every tool also declares MCP annotations
(readOnlyHint: true, idempotentHint: true, openWorldHint: false) so
clients can see this programmatically.
| Tool | Arguments | Returns |
| --------------------- | ---------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| list_apis | category?, limit? | Compact index of EPS endpoints (no request/response bodies). category is validated against the bundle's categories; all entries by default. |
| list_topics | — | Documentation topic ids: auth, errors, pricing, environments. |
| list_recipes | — | Multi-step recipe ids + names (e.g. dmt-fino-send-money, aeps-fingpay-cash-withdrawal). |
| search | query, limit? | Ranked endpoint matches for a query (ids only, no bodies). Top 10 by default; raise limit for more. |
| get_api | slug | Full detail for one endpoint (params, response fields, errors, examples). |
| get_topic | topic (auth | errors | pricing | environments) | One documentation topic. |
| get_recipe | id | One multi-step recipe (steps + branches). |
| get_faqs | tag?, query?, limit? | EPS FAQs (onboarding, auth, testing, integration, pricing, compliance, support). Filter by tag, rank by query. Answers are markdown with absolute links. |
| get_signing_snippet | language (php | java | csharp | javascript | python | go) | Paste-ready backend code to compute the request secret-key. |
| list_sdks | — | The backend SDKs that wrap every endpoint: language, package, install command, minimum runtime, docs URL. Compact — no members or examples. |
| get_sdk | language (javascript | python | php | go | java; the guide slug such as nodejs also works) | One SDK in full: install + requirements, client config options with units, every public class/method/type, file-upload values, the error and timeout contract, and a worked call() example. |
| debug_auth | timestamp?, secret_key? | Diagnose a 401: returns a known-answer test vector to check your signing against, mechanical checks on a supplied timestamp/signature, and ranked causes. Never takes an access_key. |
| get_meta | — | Bundle org/version, data source (baked or remote), this server's packageVersion, and updateAvailable (whether a newer npm release exists). |
Every answer links its human page. Results carry docsUrl, the web page a
person would read for that API, recipe, topic or FAQ. API results (list_apis,
search, get_api) also carry productUrl when the product has its own page.
Products with no page (e.g. transactions) and topics with no page
(environments) carry no URL rather than a link to a 404. get_meta returns
siteUrl. The server's MCP instructions tell agents to pass these URLs on to
the user. A bundle built before 2026-10-19 has no pages section; with one of
those, only the API docsUrl comes back.
Tiered usage: start with list_apis / search (cheap, compact), then call
get_api only for the endpoint(s) you actually need. Same pattern for
list_topics → get_topic, list_recipes → get_recipe and
list_sdks → get_sdk.
Reach for an SDK first. When the target language has one, get_sdk gives
you install, client construction and the call pattern with signing, param
validation and the error contract already handled — do not hand-roll the HMAC
secret-key. get_signing_snippet is for the languages with no SDK (it covers
csharp too) and for debugging a 401.
Errors are actionable: an unknown slug/id returns an MCP error result
(isError: true) with "did you mean" suggestions and a pointer to
search/list_apis; an invalid category fails schema validation with the
valid values listed.
Client configuration
Claude Code
claude mcp add eps --scope project -- npx -y @ekoindia/eps-context-mcp@latest--scope project writes a shared .mcp.json committed with the repo. Use
--scope user for every project on this machine, or drop the flag for local
scope (private to this checkout, not shared).
Or add to your MCP config (project .mcp.json, or ~/.claude.json for user scope):
{
"mcpServers": {
"eps": {
"command": "npx",
"args": ["-y", "@ekoindia/eps-context-mcp@latest"]
}
}
}Cursor
~/.cursor/mcp.json (or .cursor/mcp.json in a project):
{
"mcpServers": {
"eps": {
"command": "npx",
"args": ["-y", "@ekoindia/eps-context-mcp@latest"]
}
}
}opencode
opencode.json:
{
"mcp": {
"eps": {
"type": "local",
"command": ["npx", "-y", "@ekoindia/eps-context-mcp@latest"],
"enabled": true
}
}
}Continue
~/.continue/config.yaml:
mcpServers:
- name: eps
command: npx
args: ["-y", "@ekoindia/eps-context-mcp@latest"]Codex CLI
~/.codex/config.toml:
[mcp_servers.eps]
command = "npx"
args = ["-y", "@ekoindia/eps-context-mcp@latest"]Gemini CLI
~/.gemini/settings.json:
{
"mcpServers": {
"eps": {
"command": "npx",
"args": ["-y", "@ekoindia/eps-context-mcp@latest"]
}
}
}Staying up to date
The package is auto-published on every merge to main, and each publish carries
the freshest baked API bundle. To keep users current:
- Use
@latestin your config (all snippets above do).npxthen re-resolves the newest publish on each launch — no manual updates. Offline launches fall back to the npx cache; pin@<version>if you need a frozen build. - Update check. On startup the server does one best-effort request to the
npm registry (3s timeout). If a newer version is published, it logs a nudge to
stderr and sets
updateAvailableonget_meta— so an agent can tell you to switch to@latest. The check is silent on any failure (offline, proxy) and never blocks startup. SetEPS_NO_UPDATE_CHECK=1to disable it entirely (no network request).
Configuration
EPS_BUNDLE_URL (optional)
By default the server serves the bundle baked into the package. To pull a fresh
bundle at startup (e.g. the latest generated eps.json), set EPS_BUNDLE_URL:
{
"mcpServers": {
"eps": {
"command": "npx",
"args": ["-y", "@ekoindia/eps-context-mcp@latest"],
"env": { "EPS_BUNDLE_URL": "https://eps.eko.in/agent/eps.json" }
}
}
}The remote fetch is capped at 5 seconds; if it fails or times out for any
reason, the server transparently falls back to the baked bundle. get_meta
reports which source is in effect (baked or remote).
Security: backend-only signing
EPS requests are authenticated with a secret-key derived from your
access_key via HMAC-SHA256:
secret-key = base64( HMAC-SHA256( message = timestamp_ms, key = base64(access_key) ) )The get_signing_snippet tool returns paste-ready code for this in six
languages. This code is backend-only.
- The
access_keyis a secret. It must live in your server-side secret store (the snippets read it fromprocess.env/getenv) and must never be shipped to a browser or mobile client. - The signing tool only emits an algorithm template — it never embeds a real key. This MCP server holds no credentials and performs no signing or API calls itself; it only provides context and code.
Debugging a 401 without handing over a key
debug_auth is secret-free by design and there is no plan to add an
access_key parameter. Two reasons, both structural:
- This server is also reachable anonymously over HTTP, so a key in a tool argument would travel to infrastructure that deliberately holds no secrets.
- A tool argument lands in the caller's model context and its transcript.
Today an agent writes
process.env.EKO_ACCESS_KEYand never sees the value; a signing tool would teach it to read the secret out and paste it into a chat.
Instead the tool hands back a known-answer test vector — a dummy key, a
fixed timestamp, and the signature they must produce. Reproduce it with your own
code and the algorithm is proven; the 401 is then almost always provisioning
(IP allowlist, inactive key, wrong environment), which ranked_causes walks in
likelihood order. Causes EPS reports with a known 401 body status carry it in
statuses (2483 wrong developer_key, 2484 bad signature, 2485 timestamp more
than 2 minutes off or reused, 2486 timestamp not in ms, 2487 missing headers), so
match the failing response's status first; a cause without statuses is
unconfirmed, not ruled out. The clock-drift check uses that same 2-minute window
but measures against this server's clock at diagnosis time, so it is advisory. If you want a server that signs with real credentials, that is
@ekoindia/eps-transact-mcp, which takes them from the environment or per-request
headers — never as tool arguments.
License
MIT
