{"id":50948479,"url":"https://github.com/sap/aas-mcp-server","last_synced_at":"2026-06-17T23:01:12.794Z","repository":{"id":365257272,"uuid":"1237483517","full_name":"SAP/aas-mcp-server","owner":"SAP","description":"An AAS MCP adapter that exposes configured Asset Administration Shell APIs as Model Context Protocol tools, enabling LLM agents to interact with any AAS-compliant backend.","archived":false,"fork":false,"pushed_at":"2026-06-16T15:18:17.000Z","size":386,"stargazers_count":2,"open_issues_count":9,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-06-16T16:09:38.863Z","etag":null,"topics":["aas","ai-agent","asset-administration-shell","digital-twin","idta","industry-4-0","llm","mcp","model-context-protocol","openapi","python","sap-bnac"],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SAP.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","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-05-13T08:16:56.000Z","updated_at":"2026-06-16T14:38:35.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/SAP/aas-mcp-server","commit_stats":null,"previous_names":["sap/aas-mcp-server"],"tags_count":null,"template":false,"template_full_name":"SAP/repository-template","purl":"pkg:github/SAP/aas-mcp-server","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SAP%2Faas-mcp-server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SAP%2Faas-mcp-server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SAP%2Faas-mcp-server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SAP%2Faas-mcp-server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SAP","download_url":"https://codeload.github.com/SAP/aas-mcp-server/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SAP%2Faas-mcp-server/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34468766,"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-17T02:00:05.408Z","response_time":127,"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":["aas","ai-agent","asset-administration-shell","digital-twin","idta","industry-4-0","llm","mcp","model-context-protocol","openapi","python","sap-bnac"],"created_at":"2026-06-17T23:00:34.304Z","updated_at":"2026-06-17T23:01:12.789Z","avatar_url":"https://github.com/SAP.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![REUSE status](https://api.reuse.software/badge/github.com/SAP/aas-mcp-server)](https://api.reuse.software/info/github.com/SAP/aas-mcp-server)\n\n# AAS MCP Server\n\n## About this project\n\u003e OpenAPI-to-MCP bridge for Asset Administration Shell (AAS) APIs\n\nAn AAS MCP adapter that exposes configured Asset Administration Shell APIs as Model Context Protocol tools, enabling LLM agents to interact with any AAS-compliant backend.\n\n[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)\n\n## Requirements and Setup\n\n### Prerequisites\n\n1. **AAS OpenAPI Specifications** - [Download from GitHub](https://github.com/admin-shell-io/aas-specs)\n2. **AAS Backend Server** - [SAP BNAC AAS Server](https://www.sap.com/germany/products/business-network/asset-collaboration.html), [Eclipse BaSyx](https://github.com/eclipse-basyx), [FA³ST Service](https://github.com/FraunhoferIOSB/FAAAST-Service), etc.\n3. **Python 3.12+** OR **Docker**\n\n### Setup\n\n1. **Get AAS Specifications**:\n   ```bash\n   mkdir specs \u0026\u0026 cd specs\n   # Download from https://github.com/admin-shell-io/aas-specs/tree/main/schemas/openapi\n   ```\n\n2. **Create config.yaml** (copy from config.yaml.template):\n   ```yaml\n   components:\n     aas-repo:\n       official_spec: specs/AssetAdministrationShellRepositoryServiceSpecification-V3.1.1_SSP-001.yaml\n       curation:\n         allowlist:\n           - [get, \"*\"]  # All GET operations (wildcard)\n           - [post, /shells]\n   ```\n\n3. **Run**:\n   ```bash\n   # Docker (recommended)\n   docker run \\\n     -v $(pwd)/config.yaml:/app/config/config.yaml \\\n     -v $(pwd)/specs:/app/specs \\\n     -e AAS_COMPONENT=aas-repo \\\n     -e AAS_BASE_URL=http://your-backend:8080 \\\n     -i aas-mcp-server\n\n   # Or install locally\n   pip install -e .\n   aas-mcp-server --component aas-repo --base-url http://localhost:8080 --config config.yaml\n   ```\n\n## Configuration\n\n### Basic (Official Spec Only)\n\n```yaml\ncomponents:\n  aas-repo:\n    official_spec: specs/aas-repo-spec.yaml\n```\n\n### Filtered (Implementation-Specific)\n\nFilter to only endpoints your backend supports:\n\n```yaml\ncomponents:\n  aas-repo:\n    official_spec: specs/aas-repo-official.yaml\n    implementation_spec: specs/aas-supported-endpoints.yaml\n```\n\nResult: Only endpoints in **both** specs are exposed (intersection).\n\n### With Curation (Wildcards Supported)\n\nControl which operations are exposed using wildcards:\n\n```yaml\ncomponents:\n  aas-repo:\n    official_spec: specs/aas-repo-spec.yaml\n    curation:\n      allowlist:\n        # Specific operations\n        - [get, /shells]\n        - [post, /shells]\n        \n        # Wildcards\n        - [get, \"*\"]          # All GET operations on any path\n        - [\"*\", /shells]      # All methods on /shells path\n        - [\"*\", \"*\"]          # All methods on all paths (use with caution!)\n        \n      aliases:\n        GetAllAssetAdministrationShells: list_shells\n        PostAssetAdministrationShell: create_shell\n```\n\nSee [config.yaml.template](config.yaml.template) for complete options.\n\n## MCP Client Configuration\n\nThe same `aas-mcp-server` binary works with all MCP-compatible clients — the server\nlogic is identical, only the config format differs per client. Full examples for all\nclients are available in [client_config_examples.txt](client_config_examples.txt).\n\n### Claude Desktop\n\nEdit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS)\nor `%APPDATA%\\Claude\\claude_desktop_config.json` (Windows).\nSee [claude_desktop_config.example.json](claude_desktop_config.example.json) for\nthe full four-component example.\n\n```json\n{\n  \"mcpServers\": {\n    \"aas-repo\": {\n      \"command\": \"aas-mcp-server\",\n      \"args\": [\n        \"--component\", \"aas-repo\",\n        \"--base-url\", \"http://localhost:8080\",\n        \"--config\", \"/path/to/your/config.yaml\"\n      ],\n      \"env\": { \"LOG_LEVEL\": \"INFO\" }\n    }\n  }\n}\n```\n\n\n### Claude CLI (Claude Code)\n\n```bash\nclaude mcp add aas-repo \\\n  --env LOG_LEVEL=INFO \\\n  -- aas-mcp-server \\\n     --component aas-repo \\\n     --base-url http://localhost:8080 \\\n     --config /path/to/your/config.yaml\n```\n\nScope options: `--scope local` (default, current project), `--scope user` (all projects),\n`--scope project` (shared with team via `.mcp.json`).\n\n### OpenCode\n\nAdd to `opencode.json` in your project root:\n\n```json\n{\n  \"$schema\": \"https://opencode.ai/config.json\",\n  \"mcp\": {\n    \"aas-repo\": {\n      \"type\": \"local\",\n      \"command\": [\n        \"aas-mcp-server\",\n        \"--component\", \"aas-repo\",\n        \"--base-url\", \"http://localhost:8080\",\n        \"--config\", \"/path/to/your/config.yaml\"\n      ],\n      \"enabled\": true,\n      \"environment\": { \"LOG_LEVEL\": \"INFO\" }\n    }\n  }\n}\n```\n\nSee [client_config_examples.txt](client_config_examples.txt) for all four components,\nauthentication setup, and write-mode configuration for every client.\n\n## Docker Usage\n\n### Basic (stdio — local use, no auth)\n\n```bash\ndocker run \\\n  -v $(pwd)/config.yaml:/app/config/config.yaml \\\n  -v $(pwd)/specs:/app/specs \\\n  -e AAS_COMPONENT=aas-repo \\\n  -e AAS_BASE_URL=http://your-backend:8080 \\\n  -i aas-mcp-server\n```\n\n### HTTP Transport with OAuth 2.1\n\nFor remote deployments where MCP clients connect over the network:\n\n```bash\ndocker run \\\n  --network your-docker-network \\\n  -v $(pwd)/config.yaml:/app/config/config.yaml \\\n  -v $(pwd)/specs:/app/specs \\\n  -e AAS_COMPONENT=aas-repo \\\n  -e AAS_BASE_URL=http://your-backend:8080 \\\n  -e MCP_TRANSPORT=streamable-http \\\n  -e MCP_HOST=0.0.0.0 \\\n  -e MCP_PORT=8000 \\\n  -e OAUTH_ISSUER_URL=https://your-idp/realms/your-realm \\\n  -e OAUTH_JWKS_URI=https://your-idp/realms/your-realm/protocol/openid-connect/certs \\\n  -e OAUTH_SERVER_BASE_URL=http://localhost:8000 \\\n  -p 8000:8000 \\\n  aas-mcp-server\n```\n\nRegister with an MCP client (example using Claude CLI):\n\n```bash\nclaude mcp add aas-repo \\\n  --transport http \\\n  --scope user \\\n  --client-id your-oauth-client-id \\\n  http://localhost:8000/mcp\n```\n\n### Custom Config Path\n\n```bash\ndocker run \\\n  -v $(pwd)/my-config.yaml:/custom/config.yaml \\\n  -v $(pwd)/specs:/app/specs \\\n  -e CONFIG_PATH=/custom/config.yaml \\\n  -e AAS_COMPONENT=aas-repo \\\n  -e AAS_BASE_URL=http://your-backend:8080 \\\n  -i aas-mcp-server\n```\n\n## OAuth 2.1 Authorization\n\nThe server supports OAuth 2.1 + PKCE for HTTP transports. When enabled, the\nserver validates inbound Bearer tokens and forwards them to the AAS backend.\n\n### Environment variables\n\n| Variable | Required | Description |\n|---|---|---|\n| `OAUTH_ISSUER_URL` | Yes (to enable) | OAuth provider issuer URL. Auth is disabled when not set. |\n| `OAUTH_JWKS_URI` | Recommended | JWKS endpoint. Defaults to `{OAUTH_ISSUER_URL}/.well-known/jwks.json` — override for Keycloak and other non-standard providers. |\n| `OAUTH_SERVER_BASE_URL` | Required for Docker | Public URL of the MCP server as seen by clients. Must match the URL the MCP client was registered with. Avoids `0.0.0.0` appearing in resource metadata. |\n| `OAUTH_AUDIENCE` | Recommended | Expected `aud` claim. If unset, audience validation is skipped (warning logged). |\n| `OAUTH_REQUIRED_SCOPES` | Optional | Comma-separated required scopes, e.g. `aas:read,aas:write`. |\n| `MCP_RATE_LIMIT_PER_MINUTE` | Optional | Max requests per client per minute. Default: 60. |\n\n### Token forwarding\n\nThe validated Bearer token is automatically forwarded to the AAS backend on\nevery outbound request via a per-request `httpx.Auth` implementation. No\nseparate backend credentials are needed — the same OAuth provider can protect\nboth the MCP server and the AAS backend.\n\n\u003e **FastMCP version note:** Token forwarding uses `get_access_token()` from\n\u003e FastMCP's request context. If you build a custom Docker image that upgrades\n\u003e FastMCP, pin to a tested version in `pyproject.toml`. FastMCP ≥3.3 changed\n\u003e `get_http_headers()` to exclude `authorization` — any implementation relying\n\u003e on that for token forwarding will silently break. The `BearerTokenAuth` class\n\u003e in this server is not affected.\n\n### Provider JWKS paths\n\nDifferent providers use different JWKS paths. Always set `OAUTH_JWKS_URI`\nexplicitly rather than relying on the default:\n\n| Provider | `OAUTH_JWKS_URI` |\n|---|---|\n| Keycloak | `{issuer}/protocol/openid-connect/certs` |\n| Azure AD | `https://login.microsoftonline.com/{tenant}/discovery/v2.0/keys` |\n| Auth0 | `https://{domain}/.well-known/jwks.json` |\n| SAP IAS | `https://{tenant}.accounts.ondemand.com/oauth2/certs` |\n\n## Supported Components\n\n- `aas-repo` - Asset Administration Shell Repository\n- `submodel-repo` - Submodel Repository  \n- `aas-registry` - AAS Registry\n- `submodel-registry` - Submodel Registry\n\n## Testing\n\nRun tests:\n```bash\n# Unit tests only\ntests/run_tests.sh\n\n# With integration tests (requires backend on port 8081)\ntests/run_tests.sh --integration\n```\n\n## Support, Feedback, Contributing\n\nThis project is open to feature requests/suggestions, bug reports etc. via [GitHub issues](https://github.com/SAP/aas-mcp-server/issues). Contribution and feedback are encouraged and always welcome. For more information about how to contribute, the project structure, as well as additional contribution information, see our [Contribution Guidelines](CONTRIBUTING.md).\n\n## Security / Disclosure\n\n- **Read-only by default** - Write operations disabled unless `--enable-writes`\n- **Allowlist-based** - Only explicitly allowed operations exposed\n- **Wildcard patterns** - `[get, \"*\"]`, `[\"*\", /path]`, `[\"*\", \"*\"]`\n- **Pagination limits** - Max 100 items per request\n\nIf you find any bug that may be a security problem, please follow our instructions at [in our security policy](https://github.com/SAP/aas-mcp-server/security/policy) on how to report it. Please do not create GitHub issues for security-related doubts or problems.\n\n## How It Works\n\nWhen the server starts, it processes the OpenAPI specification through a pipeline before handing it to FastMCP:\n\n1. **Load** — reads the spec file and applies any overlay (rename, add descriptions, etc.)\n2. **Flatten** — resolves `$ref` inheritance chains and merges `allOf` compositions into flat schemas. This is necessary because the official IDTA AAS spec uses multi-level `allOf` + `$ref` inheritance (e.g. `AssetAdministrationShell` → `Identifiable` → `Referable`). Without flattening, FastMCP only sees the properties defined directly on the schema and misses all inherited fields like `id`, `modelType`, and `assetInformation`. Circular references are handled by keeping a `$ref` pointer at the cycle point instead of recursing infinitely.\n3. **Curate** — applies the allowlist to filter paths, enforces read-only mode, applies operation ID aliases, and caps pagination limits.\n4. **Prune** — removes `components/schemas` entries that are no longer reachable from any remaining path. This prevents FastMCP's schema validator from processing circular schemas that belonged to paths filtered out in the previous step, which would otherwise cause it to hang.\n5. **Generate** — FastMCP generates MCP tools from the processed spec and wires them to the HTTP client.\n\n\u003e **Note on `allOf` merging:** When multiple `allOf` elements define the same non-property keyword (e.g. `description`, `additionalProperties`), the first value is kept. This is safe for the standard IDTA AAS spec but may produce weaker validation constraints on specs with conflicting allOf-level keywords.\n\n## Troubleshooting\n\n### \"Configuration file not found\"\n\n**Provide config via**:\n- `--config /path/to/config.yaml`\n- `CONFIG_PATH` environment variable\n- Default: `/app/config/config.yaml`\n\n### \"official_spec file not found\"\n\n**Check**:\n- Paths in config.yaml are correct\n- Specs are mounted (Docker): `-v $(pwd)/specs:/app/specs`\n\n### OAuth / HTTP Transport\n\n#### \"Got new credentials, but server rejected them on reconnect\"\n\nToken validation is failing inside the container. Check the container logs:\n\n```bash\ndocker logs \u003ccontainer-id\u003e 2\u003e\u00261 | grep -E \"Token validation|JWKS|401|ERROR\"\n```\n\n**Common causes:**\n\n**1. Wrong JWKS path (most common with Keycloak)**\n\nThe default JWKS path `/.well-known/jwks.json` is not standard — many providers\nuse a different path. Always set `OAUTH_JWKS_URI` explicitly:\n\n```bash\n# Keycloak\n-e OAUTH_JWKS_URI=http://keycloak-host/realms/your-realm/protocol/openid-connect/certs\n\n# Verify the correct path from your provider's discovery document:\ncurl -s https://your-idp/.well-known/openid-configuration | python3 -c \\\n  \"import sys,json; print(json.load(sys.stdin)['jwks_uri'])\"\n```\n\n**2. Hostname not resolvable inside the Docker container**\n\nYour IdP hostname (e.g. `keycloak.example.localhost`) may resolve on your host\nmachine but not inside the Docker container. Verify:\n\n```bash\ndocker exec \u003ccontainer-id\u003e python3 -c \\\n  \"import socket; print(socket.gethostbyname('your-idp-hostname'))\"\n```\n\nIf it fails, add the hostname with `--add-host`:\n\n```bash\n# Find the IP your IdP resolves to on the host\npython3 -c \"import socket; print(socket.gethostbyname('your-idp-hostname'))\"\n\n# Add it to the container\ndocker run --add-host your-idp-hostname:\u003cip\u003e ...\n```\n\nIf your setup uses an nginx reverse proxy container, use the **proxy** container's\nIP — not the IdP container's IP directly. The proxy listens on port 80 and routes\nby hostname; the IdP container typically only listens on a high port (e.g. 8080)\nand does not accept plain-hostname requests on port 80.\n\n```bash\n# Find all container names and IPs on your network\ndocker network inspect your-network | python3 -c \"\nimport sys, json\ndata = json.load(sys.stdin)\nfor c in data[0].get('Containers', {}).values():\n    print(c['Name'], c.get('IPv4Address'))\n\"\n# Use the proxy container's IP (e.g. nginx-proxy), not the IdP container's IP\n\ndocker run --add-host your-idp-hostname:\u003cproxy-ip\u003e ...\n```\n\nTo verify the hostname resolves AND reaches the JWKS endpoint from inside the container:\n\n```bash\ndocker exec \u003ccontainer-id\u003e python3 -c \"\nimport urllib.request\nresp = urllib.request.urlopen('http://your-idp-hostname/realms/your-realm/protocol/openid-connect/certs', timeout=5)\nprint('JWKS status:', resp.status)\n\"\n```\n\n**3. `resource` URL mismatch (`0.0.0.0` vs `localhost`)**\n\nWhen `MCP_HOST=0.0.0.0`, the server's protected resource metadata advertises\n`http://0.0.0.0:8000/mcp` as its URL, which doesn't match `http://localhost:8000/mcp`\nthat the MCP client registered. Set `OAUTH_SERVER_BASE_URL` to the public-facing URL:\n\n```bash\n-e OAUTH_SERVER_BASE_URL=http://localhost:8000\n```\n\nVerify the metadata is correct before registering with your MCP client:\n\n```bash\ncurl -s http://localhost:8000/.well-known/oauth-protected-resource/mcp \\\n  | python3 -m json.tool\n# \"resource\" must exactly match the URL you pass to your MCP client\n```\n\n**4. Wrong Docker network**\n\nThe container must be on the same network as your AAS backend and IdP:\n\n```bash\n# List container networks\ndocker ps --format \"{{.Names}}\\t{{.Networks}}\"\n\n# Use the correct network\ndocker run --network correct-network-name ...\n```\n\n#### \"Not Found\" when browser opens for authentication\n\nThe MCP client constructed the authorization URL using the wrong endpoint. This\nhappens when the server's `/.well-known/oauth-authorization-server` returns 404\n(expected — this server is a pure resource server) and the client falls back\nincorrectly. Ensure `--client-id` is passed when registering the server\n(example using Claude CLI):\n\n```bash\nclaude mcp add aas-repo \\\n  --transport http \\\n  --scope user \\\n  --client-id your-oauth-client-id \\\n  http://localhost:8000/mcp\n```\n\n#### MCP tool succeeds but AAS backend returns 401\n\nThe MCP server accepted the token but the backend rejected it. This is a\ndifferent failure from the MCP server itself returning 401.\n\n**Symptom:** An MCP tool call returns something like:\n```\nError calling tool 'list_shells': HTTP error 401:\n```\n\n**Check the MCP server logs for the outbound request:**\n\n```bash\ndocker logs \u003ccontainer-id\u003e 2\u003e\u00261 | grep -A3 \"send_request_headers\\|aas-env\\|GET /shells\"\n```\n\nLook at the `headers` line. If `authorization` is absent, token forwarding\nis not working.\n\n**Common causes:**\n\n**a. FastMCP version changed `get_http_headers()` behaviour**\n\nFastMCP ≥3.3 explicitly excludes `authorization` from `get_http_headers()`.\nThe server uses `BearerTokenAuth` (a custom `httpx.Auth` class) to work around\nthis. If you see the header missing, verify you are running the current image:\n\n```bash\ndocker exec \u003ccontainer-id\u003e python3 -c \"\nfrom aas_mcp_server.http_client import BearerTokenAuth\nprint('BearerTokenAuth present — token forwarding is correct')\n\"\n```\n\n**b. Spring Security `issuer-uri` mismatch**\n\nSpring Security validates the `iss` claim in the token with exact string\nmatching. If the MCP server was configured with\n`OAUTH_ISSUER_URL=http://keycloak.localhost/realms/aas` but the AAS\nbackend has `issuer-uri: http://keycloak:8080/realms/aas`, Spring rejects\nthe token even though it is from the same Keycloak.\n\nDecode the token to check the `iss` claim:\n\n```bash\nTOKEN=\u003cyour-token\u003e\npython3 -c \"\nimport base64, json\npayload = '$TOKEN'.split('.')[1]\npayload += '=' * (4 - len(payload) % 4)\nprint('iss:', json.loads(base64.urlsafe_b64decode(payload)).get('iss'))\n\"\n```\n\nThe `iss` value must exactly match the `issuer-uri` in the AAS backend's\nSpring Security config. Set `OAUTH_ISSUER_URL` to whichever value the AAS\nbackend expects.\n\n#### Manually testing the full token chain\n\nTo reproduce and isolate failures before involving an MCP client:\n\n```bash\n# 1. Get a token (replace with your provider's token endpoint)\nTOKEN=$(curl -s -X POST \\\n  \"https://your-idp/realms/your-realm/protocol/openid-connect/token\" \\\n  -d \"grant_type=password\u0026client_id=your-client\u0026username=user\u0026password=pass\u0026scope=openid\" \\\n  | python3 -c \"import sys,json; print(json.load(sys.stdin)['access_token'])\")\n\n# 2. Decode the token claims\npython3 -c \"\nimport base64, json\npayload = '$TOKEN'.split('.')[1]\npayload += '=' * (4 - len(payload) % 4)\nc = json.loads(base64.urlsafe_b64decode(payload))\nprint('iss:', c.get('iss'))\nprint('aud:', c.get('aud'))\nprint('scope:', c.get('scope'))\n\"\n\n# 3. Call the MCP server — should return 200\ncurl -s -o /dev/null -w \"%{http_code}\" \\\n  -X POST http://localhost:8000/mcp \\\n  -H \"Authorization: Bearer $TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"jsonrpc\":\"2.0\",\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2025-03-26\",\"capabilities\":{},\"clientInfo\":{\"name\":\"test\",\"version\":\"1\"}},\"id\":1}'\n```\n\n## Code of Conduct\n\nWe as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone. By participating in this project, you agree to abide by its [Code of Conduct](https://github.com/SAP/.github/blob/main/CODE_OF_CONDUCT.md) at all times.\n\n## Licensing\n\nCopyright 2026 SAP SE or an SAP affiliate company and aas-mcp-server contributors. Please see our [LICENSE](LICENSE) for copyright and license information. Detailed information including third-party components and their licensing/copyright information is available [via the REUSE tool](https://api.reuse.software/info/github.com/SAP/aas-mcp-server).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsap%2Faas-mcp-server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsap%2Faas-mcp-server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsap%2Faas-mcp-server/lists"}