{"id":48528934,"url":"https://github.com/tinywasm/mcp","last_synced_at":"2026-04-07T23:30:44.532Z","repository":{"id":342325625,"uuid":"1164803486","full_name":"tinywasm/mcp","owner":"tinywasm","description":"implementation of the Model Context Protocol (MCP)","archived":false,"fork":false,"pushed_at":"2026-04-03T03:03:20.000Z","size":7028,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-03T12:22:58.548Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tinywasm.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":null,"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},"funding":{"github":["cdvelop"]}},"created_at":"2026-02-23T14:00:04.000Z","updated_at":"2026-04-03T03:03:24.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/tinywasm/mcp","commit_stats":null,"previous_names":["tinywasm/mcp"],"tags_count":20,"template":false,"template_full_name":null,"purl":"pkg:github/tinywasm/mcp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinywasm%2Fmcp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinywasm%2Fmcp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinywasm%2Fmcp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinywasm%2Fmcp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tinywasm","download_url":"https://codeload.github.com/tinywasm/mcp/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tinywasm%2Fmcp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31533823,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-07T16:28:08.000Z","status":"ssl_error","status_checked_at":"2026-04-07T16:28:06.951Z","response_time":105,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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-04-07T23:30:42.998Z","updated_at":"2026-04-07T23:30:44.521Z","avatar_url":"https://github.com/tinywasm.png","language":"Go","funding_links":["https://github.com/sponsors/cdvelop"],"categories":[],"sub_categories":[],"readme":"# tinywasm/mcp\n\u003cimg src=\"docs/img/badges.svg\"\u003e\n\nLean Go implementation of the [Model Context Protocol](https://modelcontextprotocol.io/) (MCP) over JSON-RPC 2.0. Protocol-only, WASM-safe, minimal public API.\n\n## Installation\n\n```bash\ngo get github.com/tinywasm/mcp\n```\n\n### ormc (code generation)\n\nTools use `ormc` for automatic `Schema()`, `Pointers()`, and `Validate()` generation:\n\n```bash\ngo install github.com/tinywasm/orm/cmd/ormc@latest\n```\n\n## Quickstart\n\n### 1. Define tool arguments with validation (using ormc)\n\n```go\n// Tool arguments are plain structs with validation tags\n// ormc generates Schema(), Pointers(), Validate() automatically\ntype SearchArgs struct {\n    Query string `input:\"required,min=1,max=255\"`\n    Limit int64  `input:\"min=1,max=100\"`\n}\n```\n\n### 2. Write the handler\n\n```go\nfunc handleSearch(ctx *context.Context, req mcp.Request) (*mcp.Result, error) {\n    var args SearchArgs\n    if err := req.Bind(\u0026args); err != nil {\n        return nil, err // server wraps as JSON-RPC error\n    }\n    return mcp.Text(\"found 3 results\"), nil\n}\n```\n\n### 3. Register and serve\n\n```go\nsrv, err := mcp.NewServer(mcp.Config{\n    Name:    \"my-server\",\n    Version: \"1.0.0\",\n    Auth:    mcp.NewTokenAuthorizer(\"my-secret-key\"),\n}, nil)\nif err != nil {\n    log.Fatal(err)\n}\n\nsrv.AddTool(mcp.Tool{\n    Name:        \"search\",\n    Description: \"Search items by query\",\n    InputSchema: new(SearchArgs).Schema(),\n    Resource:    \"items\",\n    Action:      'r',\n    Execute:     handleSearch,\n})\n\n// Consumer owns HTTP routing — use HandleMessage directly\nhttp.HandleFunc(\"/mcp\", func(w http.ResponseWriter, r *http.Request) {\n    body, _ := io.ReadAll(r.Body)\n    ctx := context.New()\n    ctx.Set(mcp.CtxKeyAuthToken, r.Header.Get(\"Authorization\"))\n    resp := srv.HandleMessage(\u0026ctx, body)\n    // encode resp as JSON and write to w\n})\nhttp.ListenAndServe(\":3030\", nil)\n```\n\n### 4. Tool results\n\n```go\nreturn mcp.Text(\"operation completed\"), nil   // text\nreturn mcp.JSON(\u0026MyData{Name: \"test\"})        // JSON (Fielder)\ntext, err := mcp.GetText(result)              // extract text\n```\n\n---\n\n## Authorizer\n\nmcp provides built-in implementations and accepts custom ones:\n\n```go\ntype Authorizer interface {\n    Authorize(token string) (userID string, err error)\n    Can(userID, resource string, action byte) bool\n}\n\n// Built-in:\nauth := mcp.NewTokenAuthorizer(\"my-api-key\") // token-based, Can() always true\nauth := mcp.OpenAuthorizer()                  // no auth, Can() always true\n\n// Custom (e.g. from tinywasm/user):\nauth := userModule.MCPAuthorizer()            // satisfies mcp.Authorizer\n```\n\nAuth is required — `NewServer` returns error if `Config.Auth == nil`. Use `mcp.OpenAuthorizer()` for open access.\n\n---\n\n## SSE (Streamable HTTP)\n\nOptional streaming via `SSEPublisher` interface. The consumer creates the SSE server and injects it:\n\n```go\nimport \"github.com/tinywasm/sse\"\n\nsseServer := sse.New()\n\nsrv, err := mcp.NewServer(mcp.Config{\n    Name:    \"my-server\",\n    Version: \"1.0.0\",\n    Auth:    mcp.NewTokenAuthorizer(\"secret\"),\n    SSE:     sseServer, // *sse.SSEServer satisfies mcp.SSEPublisher\n}, providers)\n```\n\nWhen SSE is present, tool list changes and notifications are published automatically. When nil, no streaming occurs.\n\n---\n\n## ToolProvider\n\nGroup related tools and their dependencies in a provider:\n\n```go\ntype CatalogProvider struct {\n    db *postgres.DB\n}\n\ntype CatalogSearchArgs struct {\n    Query    string `input:\"required,min=1,max=255\"`\n    Category string `input:\"max=50\"`\n}\n\ntype CatalogUpdateArgs struct {\n    ProductID string  `input:\"required\"`\n    Price     float64 `input:\"required,min=0\"`\n}\n\nfunc (p *CatalogProvider) Tools() []mcp.Tool {\n    return []mcp.Tool{\n        {\n            Name:        \"catalog_search\",\n            Description: \"Search product catalog\",\n            InputSchema: new(CatalogSearchArgs).Schema(),\n            Resource:    \"catalog\",\n            Action:      'r',\n            Execute:     p.handleSearch,\n        },\n        {\n            Name:        \"catalog_update\",\n            Description: \"Update product price\",\n            InputSchema: new(CatalogUpdateArgs).Schema(),\n            Resource:    \"catalog\",\n            Action:      'u',\n            Execute:     p.handleUpdate,\n        },\n    }\n}\n\nfunc (p *CatalogProvider) handleSearch(ctx *context.Context, req mcp.Request) (*mcp.Result, error) {\n    var args CatalogSearchArgs\n    if err := req.Bind(\u0026args); err != nil {\n        return nil, err\n    }\n    // ... query p.db\n    return mcp.Text(\"found 3 products\"), nil\n}\n\n// Pass providers to NewServer\nsrv, err := mcp.NewServer(config, []mcp.ToolProvider{\u0026CatalogProvider{db: db}})\n```\n\n---\n\n## WASM / Browser\n\nThe protocol core compiles with TinyGo. Server-only files (`//go:build !wasm`)\nare excluded automatically.\n\nIn browser mode, call the handler directly — no HTTP server needed:\n\n```go\nsrv, err := mcp.NewServer(config, providers)\nresponse := srv.HandleMessage(\u0026ctx, message)\n```\n\n---\n\n## API Reference\n\n| Symbol | Description |\n|--------|-------------|\n| `NewServer(config, providers)` | Create MCP server — returns `(*Server, error)` |\n| `Server.AddTool(tool)` | Register a single tool |\n| `Server.HandleMessage(ctx, msg)` | Process JSON-RPC message (WASM-safe) |\n| `Tool{Name, Description, InputSchema, Resource, Action, Execute}` | Tool definition |\n| `ToolProvider` | Interface: `Tools() []Tool` |\n| `Authorizer` | Interface: `Authorize(token) (userID, error)`, `Can(userID, resource, action) bool` |\n| `SSEPublisher` | Interface: `Publish(data, channel)` (build `!wasm`) |\n| `NewTokenAuthorizer(apiKey)` | Token-based authorizer |\n| `OpenAuthorizer()` | Open access authorizer |\n| `Request` | Incoming tool call |\n| `Request.Bind(target)` | Decode + validate arguments |\n| `Result` | Tool call result |\n| `Text(s)` | Create text result |\n| `JSON(data)` | Create JSON result |\n| `GetText(result)` | Extract text from result |\n| `Config` | Server configuration: `Name`, `Version`, `Auth`, `SSE` |\n| `CtxKeySessionID` | Context key for session ID |\n| `CtxKeyUserID` | Context key for authenticated user ID |\n| `CtxKeyAuthToken` | Context key for auth token |\n\n---\n\nSee [docs/WHY_ARQ.md](docs/WHY_ARQ.md) for architecture decisions and trade-offs.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftinywasm%2Fmcp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftinywasm%2Fmcp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftinywasm%2Fmcp/lists"}