{"id":51134584,"url":"https://github.com/polterguy/mcp","last_synced_at":"2026-06-25T16:01:41.521Z","repository":{"id":364933411,"uuid":"1269012629","full_name":"polterguy/mcp","owner":"polterguy","description":"MCP module for Magic Cloud","archived":false,"fork":false,"pushed_at":"2026-06-15T05:51:01.000Z","size":11,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-06-15T07:23:30.590Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/polterguy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-14T07:46:07.000Z","updated_at":"2026-06-15T05:51:05.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/polterguy/mcp","commit_stats":null,"previous_names":["polterguy/mcp"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/polterguy/mcp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/polterguy%2Fmcp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/polterguy%2Fmcp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/polterguy%2Fmcp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/polterguy%2Fmcp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/polterguy","download_url":"https://codeload.github.com/polterguy/mcp/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/polterguy%2Fmcp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34782137,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-25T02:00:05.521Z","response_time":101,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-06-25T16:01:39.420Z","updated_at":"2026-06-25T16:01:41.496Z","avatar_url":"https://github.com/polterguy.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# MCP for Magic\n\nA [Model Context Protocol](https://modelcontextprotocol.io) server, implemented entirely in\nHyperlambda. It exposes your Magic backend's dynamic endpoints as MCP **tools**, so MCP\nclients (Claude Desktop, Cursor, the Claude API, etc.) can discover and invoke them.\n\nNo C# code and no recompile — these are interpreted `.hl` files. Drop the folder in,\nauthenticate, and the server is live.\n\n- **Endpoint:** `POST /magic/modules/mcp/mcp`\n- **Protocol:** JSON-RPC 2.0 over HTTP (plain-JSON responses; a spec-compliant subset of the\n  Streamable HTTP transport — no SSE)\n\n## How it works\n\nThe core idea: **every dynamic endpoint under `modules/` is an MCP tool.**\n\n- Tool **discovery** reuses the `[endpoints.list]` slot — the same metadata (arguments,\n  description, authorization) Magic already exposes for its own UI.\n- Tool **execution** reuses the `[execute-file]` slot — the same in-process invocation Magic's\n  own AI function-calling uses.\n\nSo an MCP client reaches the exact same endpoints, enforcing the exact same per-endpoint\nauthorization, as an HTTP client would. There is no separate tool registry to maintain.\n\n## Files\n\n| File | Role |\n| --- | --- |\n| `mcp.post.hl` | The JSON-RPC dispatcher (the endpoint). |\n| `tools.hl` | Internal helper — has no HTTP verb in its name, so it is **not** an endpoint. Returns the canonical tool catalogue (`name`, `file`, `description`, `input`) consumed by both `tools/list` and `tools/call`. This single source of truth guarantees a client can only invoke a tool that was also listed. |\n\n## Supported methods\n\n| Method | Behaviour |\n| --- | --- |\n| `initialize` | Handshake. Echoes the client's `protocolVersion` when supplied, advertises the `tools` capability, returns `serverInfo`. |\n| `ping` | Liveness probe. |\n| `tools/list` | One descriptor per exposed endpoint, each with a JSON-Schema `inputSchema` derived from the endpoint's `[.arguments]`. |\n| `tools/call` | Resolves the tool name, invokes the underlying endpoint with the supplied arguments, returns the result as a `text` content block (the endpoint's JSON result, stringified). A throwing endpoint is reported as an `isError` content block — see [Errors](#errors). |\n| notifications | Any JSON-RPC notification (a message with no `id`, e.g. `notifications/initialized`) is acknowledged with HTTP `202` and an empty body. |\n| unknown method / tool | JSON-RPC error `-32601` (method not found) / `-32602` (unknown tool). |\n\n## Errors\n\nThe two MCP error channels are kept distinct:\n\n- **Protocol errors** — malformed or unroutable requests (unknown method, unknown tool) come back\n  as a JSON-RPC `error` object (`-32601` / `-32602`).\n- **Tool execution errors** — when the underlying endpoint throws, the call still returns a\n  JSON-RPC `result`, but with `\"isError\": true` and the message in the `text` content block, so the\n  model sees the failure in-band. Exceptions the endpoint marked `public` relay their real message;\n  all others return a generic `\"Tool execution failed\"` and are `log.error`'d server-side — internal\n  detail is never leaked to the client, but never silently swallowed either.\n\n## Authentication\n\nThe endpoint requires an **authenticated Magic user** — the client sends its Magic JWT as a\nbearer token (`Authorization: Bearer \u003ctoken\u003e`).\n\n`tools/call` runs the target endpoint through that same ticket, so the endpoint's own\n`[auth.ticket.verify]` still applies: a non-`root` user calling a `root`-only tool is rejected\nby the tool itself.\n\nTo make the server anonymous, remove the `auth.ticket.verify` line from `mcp.post.hl`.\n\n## What is exposed\n\nBy default, **every endpoint under `modules/` except this MCP module itself.** The filter lives\nin `tools.hl`:\n\n```\nstrings.starts-with:x:@.dp/#/*/path\n   .:magic/modules/\n```\n\nTo expose endpoints on an explicit opt-in basis instead, add a marker (e.g. a `.mcp:bool:true`\nnode) to the endpoints you want exposed and tighten this filter accordingly.\n\n### Tool naming\n\nA tool name is `\"\u003cverb\u003e_\" + \u003cpath below modules/ with \"/\" replaced by \"_\"\u003e`, e.g.\n`GET /magic/modules/crm/customers` becomes `get_crm_customers`. Resolution is done by matching\nthis name against the catalogue, so the mapping never has to be reversed.\n\n### Argument type mapping\n\n`[.arguments]` types are mapped to JSON-Schema types as follows:\n\n| Hyperlambda | JSON Schema |\n| --- | --- |\n| `short`, `int`, `long` | `integer` |\n| `float`, `double`, `decimal` | `number` |\n| `bool` | `boolean` |\n| everything else (`string`, `date`, `guid`, …) | `string` |\n\n## Testing\n\n```bash\nTOKEN=...   # a Magic JWT\nURL=localhost:5000/magic/modules/mcp/mcp\n\n# Handshake\ncurl -s $URL -H \"Authorization: Bearer $TOKEN\" -H 'Content-Type: application/json' \\\n  -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2024-11-05\"}}' | jq .\n\n# List tools\ncurl -s $URL -H \"Authorization: Bearer $TOKEN\" -H 'Content-Type: application/json' \\\n  -d '{\"jsonrpc\":\"2.0\",\"id\":2,\"method\":\"tools/list\"}' | jq .\n\n# Call a tool\ncurl -s $URL -H \"Authorization: Bearer $TOKEN\" -H 'Content-Type: application/json' \\\n  -d '{\"jsonrpc\":\"2.0\",\"id\":3,\"method\":\"tools/call\",\"params\":{\"name\":\"get_crm_customers\",\"arguments\":{}}}' | jq .\n```\n\n## Connecting a client\n\nPoint any HTTP/Streamable-HTTP MCP client at the endpoint and supply the bearer token, e.g.:\n\n```json\n{\n  \"mcpServers\": {\n    \"magic\": {\n      \"url\": \"https://your-host/magic/modules/mcp/mcp\",\n      \"headers\": { \"Authorization\": \"Bearer YOUR_MAGIC_JWT\" }\n    }\n  }\n}\n```\n\nClients that only speak stdio can bridge to this HTTP endpoint with a tool such as\n[`mcp-remote`](https://www.npmjs.com/package/mcp-remote).\n\n## Known limitations (v1)\n\n- `ping` returns `\"result\":null` and a description-less tool returns `\"description\":null`\n  (the lambda-to-JSON serializer renders childless nodes as scalars). Clients tolerate this.\n- An install with **no** `modules/` endpoints would serialize `tools` as `null` rather than `[]`.\n- Tool names are not truncated to the 64-character limit some clients enforce, which could\n  matter for very deeply nested module paths.\n- Transport is request/response JSON only; there is no SSE stream or server-initiated message.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpolterguy%2Fmcp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpolterguy%2Fmcp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpolterguy%2Fmcp/lists"}