Skip to content

Stage 1: extract imcp2-core (transport/OAuth-agnostic components) - #77

Merged
aterga merged 1 commit into
mainfrom
claude/secondary-mcp-local-deploy-jpof9i
Aug 25, 2026
Merged

aterga merged 1 commit into
mainfrom
claude/secondary-mcp-local-deploy-jpof9i

Conversation

@aterga

@aterga aterga commented Jul 23, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Stage 1 of the local-deployment design (the design docs merged in #148): extract imcp2-core, the transport/OAuth-agnostic component crate both server binaries build on, leaving imcp2 as the hosted composition (the OAuth 2.1 authorization server, the streamable-HTTP transport, the axum routers, metrics, and the PocketIC e2e harness) that depends on core and re-exports its public items. No behavior change to the imcp2 binary.

Related issues

Implements Implementation Stages → Stage 1 of the design docs merged in #148.

Changes

  • Workspace + new crate. imcp2-core carries identities, calls, discover, management, skills, tools (the whole #[tool_router] surface stays co-located with IcTools), the compiled-in static/ references, and the connect assets. Shared version pins move to [workspace.dependencies].
  • New iiconnect module — the II connect-handshake primitives lifted out of auth.rs (the /mcp link builder, the pinned callback page rendered to plain html+csp values, the delegation-chain parser + 64 KB bound, the #4091 allow-list path), re-parameterised on plain values. auth.rs keeps thin axum wrappers with identical routes, headers, and bytes.
  • Session seam. IcTools::new takes a SessionSource: Bearer resolves the session per request from the AuthedSession extension (now a core type, read via http::request::Parts so core does not depend on axum); Singleton pins one login-established session for a single-user binary. All 13 session lookups go through current_session_id.
  • imcp2 re-exports core's public items (Agent, IiInstance, SessionGauges, ic_agent, IC_URL), so embedders' imcp2::… imports keep compiling. rmcp's unused auth feature is dropped.
  • Infra: Dockerfile/build.sh copy crates/; CI builds/tests --workspace; the publish workflow checks both versions against the tag and publishes imcp2-core before imcp2 (core's first release is manual, like imcp2's 0.1.0 was, since a trusted publisher can only be configured on an existing crate).

Testing

  • cargo build --locked --workspace --all-targets
  • cargo test --locked --workspace --all-targets — 206 passed, 0 failed (hosted: 52 lib + 10 bin + 9 router-contract, all pre-existing and unchanged; core: 135 — the moved suites plus new iiconnect tests)
  • cargo check --features e2e --all-targets (PocketIC harness still compiles)
  • cargo publish --locked --dry-run -p imcp2-core and cargo package --locked --no-verify -p imcp2 rehearse cleanly; the imcp2 .crate contains no crates//static/ leak
  • Exit criterion: imcp2-core's dependency graph contains no axum, no direct tower-http, no prometheus, no OAuth code (cargo tree; tower-http 0.6 appears only transitively inside reqwest/rmcp, exactly as before the split)
  • rustfmt/clippy: no new warnings introduced (the tree's pre-existing rustfmt drift and 6 pre-existing clippy nits in moved code are left untouched to keep the move reviewable)

Checklist


🤖 Generated with Claude Code

https://claude.ai/code/session_01AqNkpMQiQHzYxC2djTfvBK

@aterga aterga changed the title Scope a secondary MCP server instance for local deployments Scope a minimal local MCP binary (stdio, no OAuth, production II) Jul 23, 2026
@aterga
aterga requested a balanced review from Copilot July 27, 2026 13:24

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a scoping/design document for a separate “run-it-yourself” local MCP server binary that communicates over stdio, targets mainnet IC plus production Internet Identity, and removes the hosted OAuth 2.1 authorization-server layer while retaining an II browser-based delegation handshake.

Changes:

  • Add a draft scoping document defining the local-deployment model (stdio transport, no OAuth) and its security assumptions.
  • Propose a crate/binary layout (imcp2 core + imcp2-local) and a feature-gated hosted surface to keep the existing deployed imcp2 binary name unchanged.
  • Document verified dependency-stripping opportunities and a minimal tool/session seam for a singleton local session.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@aterga aterga mentioned this pull request Jul 29, 2026
4 of 7 tasks
@aterga
aterga force-pushed the claude/secondary-mcp-local-deploy-jpof9i branch from 38fb07f to ffbfaba Compare August 20, 2026 15:03
@aterga aterga changed the title Scope a minimal local MCP binary (stdio, no OAuth, production II) Design doc: IMCP2 local deployment (minimal stdio binary, no OAuth) Aug 20, 2026
@aterga aterga changed the title Design doc: IMCP2 local deployment (minimal stdio binary, no OAuth) IMCP2 local deployment: design docs + Stage 1 (extract imcp2-core) Aug 24, 2026
@aterga aterga changed the title IMCP2 local deployment: design docs + Stage 1 (extract imcp2-core) Stage 1: extract imcp2-core (transport/OAuth-agnostic components) Aug 24, 2026
@aterga
aterga changed the base branch from main to claude/secondary-mcp-local-deploy-jpof9i-docs August 24, 2026 10:32
Base automatically changed from claude/secondary-mcp-local-deploy-jpof9i-docs to main August 25, 2026 09:58
Stage 1 of the local-deployment design (docs/scoping-local-deployment.md):
move the components both server binaries build on into a new imcp2-core
workspace member, leaving imcp2 as the hosted composition (the OAuth 2.1
authorization server, the streamable-HTTP transport, the axum routers,
metrics, and the PocketIC e2e harness) that depends on core and
re-exports its public items, so embedders' imcp2::… imports keep
compiling.

- imcp2-core carries identities, calls, discover, management, skills,
  and tools (the whole #[tool_router] surface stays co-located with
  IcTools), plus the compiled-in static/ references and connect assets.
- New iiconnect module: the II connect-handshake primitives lifted out
  of auth.rs (the /mcp link builder, the pinned callback page rendered
  to plain html+csp values, the delegation-chain parser, the #4091
  allow-list path), re-parameterised on plain values; auth.rs keeps
  thin axum wrappers with identical routes, headers, and bytes.
- Session seam: IcTools::new takes a SessionSource — Bearer resolves
  the session per request from the AuthedSession extension (now a core
  type read via http::request::Parts, so core does not depend on axum),
  Singleton pins one login-established session for a single-user
  binary. The 13 session lookups go through current_session_id.
- rmcp's unused `auth` feature is dropped; shared version pins move to
  [workspace.dependencies].
- Dockerfile/build.sh copy crates/; CI and the publish workflow become
  workspace-aware (lockstep versions, imcp2-core publishes before
  imcp2; its first release is manual, like imcp2's 0.1.0 was).

imcp2-core's dependency graph contains no axum, tower-http (as a direct
dependency), prometheus, or OAuth code. The imcp2 binary's behavior is
unchanged: all 71 hosted tests pass as before, and the 135 core tests
(moved plus new iiconnect coverage) pass standalone.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AqNkpMQiQHzYxC2djTfvBK
@aterga
aterga force-pushed the claude/secondary-mcp-local-deploy-jpof9i branch from 97f2621 to 3347c7a Compare August 25, 2026 09:58
@aterga
aterga marked this pull request as ready for review August 25, 2026 10:00
@aterga
aterga requested review from a team and Copilot August 25, 2026 10:00

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 13 out of 24 changed files in this pull request and generated no new comments.

Suppressed comments (2)

crates/imcp2-core/src/tools.rs:1526

  • Singleton(String) is immutable and always populated, so the planned local server cannot construct IcTools before its lazy login or replace the session after expiry/revocation. The merged design requires a shared Option<String> slot that the login wrapper can fill and replace (docs/scoping-local-deployment.md:437-457). Model Singleton around a cloneable mutable session handle (and expose its read/write API) now; otherwise Stage 2 must break this newly published seam or restart the MCP server for every reauthentication.
    crates/imcp2-core/src/tools.rs:85
  • The new session seam is not exercised by the moved tool tests. The existing e2e check only proves a valid token passes require_token; it never invokes a session-dependent tool, so a broken http::request::Parts/AuthedSession lookup would make all 13 authenticated tools report “needs an authenticated session” while the suite still passes. Add coverage for both the hosted Bearer extension path and the local singleton slot (including replacement after re-login).

@aterga
aterga requested a review from sea-snake August 25, 2026 13:40
@aterga
aterga merged commit d47b4b5 into main Aug 25, 2026
8 checks passed
aterga pushed a commit that referenced this pull request Aug 28, 2026
…ternetcomputer.org

The landing page and its /privacy-policy, /support and /terms subpages
existed twice: served by this binary from src/assets/, and mirrored in
dfinity/internetcomputer-org (public/icp-mcp/, served at
internetcomputer.org/icp-mcp/). Two copies of legal pages drift — the
mirror carried this branch's revisions before any imcp2 release could —
so the internetcomputer-org copy becomes the only one, and this origin
stops serving pages of its own:

- The four asset pages are deleted. connect-error.html and favicon.svg
  stay: they are the OAuth connect flow's, not the landing site's, and
  the connect/callback screens link /favicon.svg for their tab icon.
- /, /privacy-policy, /support and /terms answer with permanent
  redirects (308) to the same paths under
  https://internetcomputer.org/icp-mcp/ — trailing-slash targets, so a
  client lands in one hop. Every published link keeps working: the
  directory listings' policy URLs, bookmarks, search results.
- /sitemap.xml is gone (a sitemap must list same-origin content, and
  this origin has none); robots.txt stays to keep crawlers off the
  machine surface, minus the sitemap reference, and site_metadata_router
  no longer needs PUBLIC_URL. /status/ is untouched — the live dashboard
  is this deployment's own monitoring surface, published by Caddy.
- Tests follow: the sitemap and page-content tests are replaced by a
  redirect test pinning all four absolute targets and a robots test
  asserting no sitemap is advertised.
- README and the directory-submission docs now name
  internetcomputer.org/icp-mcp/ as the pages' one home, with the old
  URLs redirecting from the release that ships this change.

The earlier commits on this branch revised the pages' text in place;
that text now lives in dfinity/internetcomputer-org#76 / #77, which is
what makes this deletion safe: nothing is lost, one copy remains.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xpg83AWtkQo34jbMxpX8WB
aterga pushed a commit that referenced this pull request Aug 28, 2026
Two conflicts, both from #164 touching the privacy policy this branch
deletes:

- src/assets/privacy-policy.html: modified on main (the third-party
  recipients list drops skills.internetcomputer.org — skills are now
  served from the reviewed bundle compiled into the binary, so no
  network fetch to disclose), deleted here. The deletion stands; the
  content change is ported to the page's one home in
  dfinity/internetcomputer-org (the #77 re-sync branch), where the
  policy now lives.
- docs/anthropic-directory-submission.md: both sides rewrote the
  "Publication venue" paragraph. Kept this branch's new-home framing,
  folding in main's note about what the refreshed text carries (the
  identifier-linkability wording and the updated third-party list).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xpg83AWtkQo34jbMxpX8WB
sea-snake added a commit that referenced this pull request Aug 28, 2026
The ship step has failed on every push to main since #77 landed on Aug 25:

    >> shipping binary + static assets
    tar: static: Cannot stat: No such file or directory
    tar: Exiting with failure status due to previous errors

#77 moved the last repo-root static/ files (candid-reference.md,
candid-textual-syntax.md, oql-primer.md) into imcp2-core, and updated
build.sh's Docker context for the new layout (`COPY static ./static` became
`COPY crates ./crates`). deploy.sh's SSH ship of the same directory was
missed, so it now tars a path that isn't there.

Nothing needed shipping in the first place: those three files were already
compiled in with `include_str!` before the split (src/tools.rs at d142a49,
the last commit that deployed green), as is every asset the server serves
today. Neither the Caddyfile nor the systemd unit reads anything from
$REMOTE_DIR/static, so what landed there was never opened.

The binary is untouched by this: same root-package `imcp2`, same
`cargo build --release`, same artifact, same destination. Deliberately not
narrowing the build to `-p imcp2` in this change — workspace feature
unification means building one member alone can resolve a different feature
set, and the host should get exactly the binary this pipeline produced
before it broke.

A host deployed before Aug 25 keeps a stale /opt/imcp2/static; it is unread
and this change does not remove it.

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
aterga added a commit that referenced this pull request Aug 31, 2026
…old page paths redirect permanently (#165)

* Remove financial-operation references from the Terms of Service

The Terms still described the Service in financial vocabulary: "never
holds your funds" / "non-custodial" (section 1), "moving tokens,
spending cycles, installing code, and deleting canisters" (section 3),
and "loss of tokens, cycles, or other assets" (section 8). That
language no longer matches the served surface — the funding and
canister-management tools are not served (#153, #154, #158) and
canister_update_call refuses the ledger methods — and, like the tool
descriptions (per review in #154), the page should stay free of
financial language rather than mention-and-deny.

Rephrase those passages without financial vocabulary while keeping
their substance and the user-responsibility posture:

- Section 1 describes the Service as reading data applications hold
  for the user and submitting actions to them, and states it never
  holds long-term credentials — only the delegated, time-limited
  session authorization. (This also stops claiming canister
  management, which the served tool set no longer offers.)
- Section 2 now states explicitly that requests made under the user's
  authorization are treated as theirs and are their sole
  responsibility.
- Section 3 keeps irreversibility front and center: an action can
  permanently change or delete data an application holds for the
  user, what an action does is defined by the receiving application,
  and nothing can be undone once the network accepts it.
- Section 8's liability examples drop the asset enumeration; the
  general damages language still covers everything it covered.

Bump the effective date for the revision (adjust to the release date
at cut time, as was done for August 3).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xpg83AWtkQo34jbMxpX8WB

* State the discoverability-based obligation of app developers in the Terms and Privacy Policy

Application developers who want their applications' operations supported
through the Service must comply with the ICP MCP Privacy Policy and
accept the Terms of Service. They assert both by implementing the
service discoverability instructions at
https://docs.internetcomputer.org/guides/frontends/service-discoverability/

- Terms, section 4 (Third Parties): new paragraph stating the
  obligation, linking the Privacy Policy and the discoverability guide.
- Privacy Policy, section 2 (Who Receives Data), "The applications you
  choose" recipient: matching sentence referring the developer to the
  Terms and the discoverability guide; effective date moves to
  August 28, 2026 per section 8 (align with the shipping release at
  cut time, as for August 3).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xpg83AWtkQo34jbMxpX8WB

* Fix the developer-obligation wording: acceptance and duty, not compliance with a notice

Review on the mirrored copy (dfinity/internetcomputer-org#76) caught a
real contradiction in the wording added by the previous commit. The
Privacy Policy states twice that application processing is governed by
each application's own policy and not by this Privacy Policy (the scope
carve-out, and the same "applications you choose" paragraph the
sentence was added to), so requiring developers to "comply with" it
both contradicted that scope and named no conduct: the Policy is a
notice about our processing and carries no developer-facing duties.

Reframe so the obligation is coherent and actionable, keeping the
acceptance-by-implementation mechanism intact:

- The developer accepts the Terms by implementing the discoverability
  instructions. Acceptance of a contract is something a third party can
  do; "compliance" with our privacy notice is not.
- The duty now lives in the Terms, where duties belong: handle personal
  data reaching them through the Service lawfully and under their own
  privacy policy, and keep that policy accurate and available.
- Both pages now say what the Privacy Policy actually is for the
  developer: it describes what the Service discloses to an
  application, and does not govern what the application does next.
  That agrees with the scope carve-out instead of fighting it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xpg83AWtkQo34jbMxpX8WB

* Drop the landing site from the server; redirect to its one home on internetcomputer.org

The landing page and its /privacy-policy, /support and /terms subpages
existed twice: served by this binary from src/assets/, and mirrored in
dfinity/internetcomputer-org (public/icp-mcp/, served at
internetcomputer.org/icp-mcp/). Two copies of legal pages drift — the
mirror carried this branch's revisions before any imcp2 release could —
so the internetcomputer-org copy becomes the only one, and this origin
stops serving pages of its own:

- The four asset pages are deleted. connect-error.html and favicon.svg
  stay: they are the OAuth connect flow's, not the landing site's, and
  the connect/callback screens link /favicon.svg for their tab icon.
- /, /privacy-policy, /support and /terms answer with permanent
  redirects (308) to the same paths under
  https://internetcomputer.org/icp-mcp/ — trailing-slash targets, so a
  client lands in one hop. Every published link keeps working: the
  directory listings' policy URLs, bookmarks, search results.
- /sitemap.xml is gone (a sitemap must list same-origin content, and
  this origin has none); robots.txt stays to keep crawlers off the
  machine surface, minus the sitemap reference, and site_metadata_router
  no longer needs PUBLIC_URL. /status/ is untouched — the live dashboard
  is this deployment's own monitoring surface, published by Caddy.
- Tests follow: the sitemap and page-content tests are replaced by a
  redirect test pinning all four absolute targets and a robots test
  asserting no sitemap is advertised.
- README and the directory-submission docs now name
  internetcomputer.org/icp-mcp/ as the pages' one home, with the old
  URLs redirecting from the release that ships this change.

The earlier commits on this branch revised the pages' text in place;
that text now lives in dfinity/internetcomputer-org#76 / #77, which is
what makes this deletion safe: nothing is lost, one copy remains.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Xpg83AWtkQo34jbMxpX8WB

---------

Co-authored-by: Claude <noreply@anthropic.com>
aterga pushed a commit that referenced this pull request Sep 22, 2026
…e redirect caveats

OpenAI's submission guide still called domain verification blocker 1: the
gateway front on mcp.internetcomputer.org answers
/.well-known/openai-apps-challenge with a redirect, so the app's route never
sees the portal's check. That is true and irrelevant. OpenAI's submission
docs accept the challenge on "the MCP host name or a parent host name; paths
are ignored", and the parent origin already serves the token:
dfinity/internetcomputer-org#99 (2026-09-03) commits it at
public/.well-known/openai-apps-challenge, and
https://internetcomputer.org/.well-known/openai-apps-challenge returns
exactly the token as text/plain (re-verified 2026-09-22). Section 1 now
records that, tells the submitter to choose internetcomputer.org as the
challenge base, and keeps the app route and repository secret as the
fallback for a portal that insists on the server host. The header callout
and the submission-day checklist say the same: the gateway item is done, the
secret item is conditional.

Both guides also carried caveats that have expired: "the old
mcp.internetcomputer.org URL redirects there from the release that ships
#165" (#165 merged 2026-08-28 and the gateway redirects those paths as well)
and "dfinity/internetcomputer-org#77 refreshes its text to the current
draft" (#77 merged 2026-08-28). Those read as pending work; they now state
the redirect as a fact. The Anthropic guide's reviewer-access text and its
test-credentials draft still sent reviewers to https://mcp.internetcomputer.org
for setup instructions; that origin redirects to the landing page, so name
the page itself, https://internetcomputer.org/icp-mcp/. The OpenAI support
row now names the public status page rather than "the status dashboard",
which the support page no longer links.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TGhwpdTbUqQbR5AiiN8Ljw
aterga pushed a commit that referenced this pull request Sep 22, 2026
…e redirect caveats

OpenAI's submission guide still called domain verification blocker 1: the
gateway front on mcp.internetcomputer.org answers
/.well-known/openai-apps-challenge with a redirect, so the app's route never
sees the portal's check. That is true and irrelevant. OpenAI's submission
docs accept the challenge on "the MCP host name or a parent host name; paths
are ignored", and the parent origin already serves the token:
dfinity/internetcomputer-org#99 (2026-09-03) commits it at
public/.well-known/openai-apps-challenge, and
https://internetcomputer.org/.well-known/openai-apps-challenge returns
exactly the token as text/plain (re-verified 2026-09-22). Section 1 now
records that, tells the submitter to choose internetcomputer.org as the
challenge base, and keeps the app route and repository secret as the
fallback for a portal that insists on the server host. The header callout
and the submission-day checklist say the same: the gateway item is done, the
secret item is conditional.

Both guides also carried caveats that have expired: "the old
mcp.internetcomputer.org URL redirects there from the release that ships
#165" (#165 merged 2026-08-28 and the gateway redirects those paths as well)
and "dfinity/internetcomputer-org#77 refreshes its text to the current
draft" (#77 merged 2026-08-28). Those read as pending work; they now state
the redirect as a fact. The Anthropic guide's reviewer-access text and its
test-credentials draft still sent reviewers to https://mcp.internetcomputer.org
for setup instructions; that origin redirects to the landing page, so name
the page itself, https://internetcomputer.org/icp-mcp/. The OpenAI support
row now names the public status page rather than "the status dashboard",
which the support page no longer links.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TGhwpdTbUqQbR5AiiN8Ljw
aterga added a commit that referenced this pull request Sep 22, 2026
…e redirect caveats (#196)

OpenAI's submission guide still called domain verification blocker 1: the
gateway front on mcp.internetcomputer.org answers
/.well-known/openai-apps-challenge with a redirect, so the app's route never
sees the portal's check. That is true and irrelevant. OpenAI's submission
docs accept the challenge on "the MCP host name or a parent host name; paths
are ignored", and the parent origin already serves the token:
dfinity/internetcomputer-org#99 (2026-09-03) commits it at
public/.well-known/openai-apps-challenge, and
https://internetcomputer.org/.well-known/openai-apps-challenge returns
exactly the token as text/plain (re-verified 2026-09-22). Section 1 now
records that, tells the submitter to choose internetcomputer.org as the
challenge base, and keeps the app route and repository secret as the
fallback for a portal that insists on the server host. The header callout
and the submission-day checklist say the same: the gateway item is done, the
secret item is conditional.

Both guides also carried caveats that have expired: "the old
mcp.internetcomputer.org URL redirects there from the release that ships
#165" (#165 merged 2026-08-28 and the gateway redirects those paths as well)
and "dfinity/internetcomputer-org#77 refreshes its text to the current
draft" (#77 merged 2026-08-28). Those read as pending work; they now state
the redirect as a fact. The Anthropic guide's reviewer-access text and its
test-credentials draft still sent reviewers to https://mcp.internetcomputer.org
for setup instructions; that origin redirects to the landing page, so name
the page itself, https://internetcomputer.org/icp-mcp/. The OpenAI support
row now names the public status page rather than "the status dashboard",
which the support page no longer links.


Claude-Session: https://claude.ai/code/session_01TGhwpdTbUqQbR5AiiN8Ljw

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants